Skip to content

UnitVectorY-Labs/jsonschema4springboot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

License Active Maven Central javadoc codecov

jsonschema4springboot

Add JSON Schema Validation to Spring Boot 3 with Annotations

Purpose

This library provides an annotation for deserializing JSON in Spring Boot 3 to include JSON Schema validation as part of the process using the networknt/json-schema-validator library. This replaces the @RequestBody annotation with the @ValidateJsonSchema annotation that allows the JSON Schema to be specified for a specific payload when parsing it into an object.

This is an opinionated design first approach to implementing the APIs where the input validation logic lives in the JSON Schema instead of in the Java code. While the JSON Schema and POJO are not validated against one another, the flexible input validation provided by a JSON Schema is intended to reduce the complexity of the API implementation.

Getting Started

This library requires Java 17 and Spring Boot 3 and is available in the Maven Central Repository:

<dependency>
    <groupId>com.unitvectory</groupId>
    <artifactId>jsonschema4springboot</artifactId>
    <version>0.0.3</version>
</dependency>

Usage

For a Spring Boot 3 project to utilize the @ValidateJsonSchema annotation the ValidateJsonSchemaArgumentResolver class must be registered with Spring Boot using the addArgumentResolvers method. This can be accomplished with the following code.

package example;

import java.util.List;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.unitvectory.jsonschema4springboot.ValidateJsonSchemaArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;

@Configuration
public class JsonValidationConfiguration implements WebMvcConfigurer {

    @Override
    public void addArgumentResolvers(
            @SuppressWarnings("null") List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(ValidateJsonSchemaArgumentResolver.newInstance());
    }
}

Each request can have a schema defined, in this example the schema is located at src/main/resources/jsonschema.json. While this example shows a draft-07 JSON Schema example, all versions of JSON Schema supported by networknt/json-schema-validator can be used.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "value": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9]+$"
    }
  },
  "required": ["value"],
  "additionalProperties": false
}

The following example shows a controller that utilizies the prior JSON Schema with a nominal API implementation.

package example;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import com.unitvectory.jsonschema4springboot.ValidateJsonSchemaVersion;
import com.unitvectory.jsonschema4springboot.ValidateJsonSchema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@RestController
public class ExampleController {

    @PostMapping(path = "/example", consumes = MediaType.APPLICATION_JSON_VALUE,
            produces = MediaType.APPLICATION_JSON_VALUE)
    public ExampleResponse example(@ValidateJsonSchema(version = ValidateJsonSchemaVersion.V7,
            schemaPath = "classpath:jsonschema.json") ExampleRequest request) {
        // Trivial API example
        return new ExampleResponse(request.getValue().length());
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class ExampleRequest {
        private String value;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class ExampleResponse {
        private int length;
    }
}

In the case the JSON Schema does not validate a ValidateJsonSchemaException will be thrown which can be mapped to an API response. The ValidateJsonSchemaFailedResponse class is provided and provides a simple error object listing the JSON Schema validation errors.

{
  "message": "JSON validation failed",
  "details": ["$: required property 'value' not found"]
}

To return this error an exception mapper must be provided. However, this is flexible and a different error structure can be used specific to an implementation.

package example;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import com.unitvectory.jsonschema4springboot.ValidateJsonSchemaException;
import com.unitvectory.jsonschema4springboot.ValidateJsonSchemaFailedResponse;

@ControllerAdvice
public class JsonValidationExceptionHandler {

    @ExceptionHandler(ValidateJsonSchemaException.class)
    public ResponseEntity<ValidateJsonSchemaFailedResponse> onValidateJsonSchemaException(
            ValidateJsonSchemaException ex) {
        return ResponseEntity.badRequest().body(new ValidateJsonSchemaFailedResponse(ex));
    }
}