dextertron_
dextertron_

Reputation: 1041

How to customize error messages for JSONSchema?

Is there a way to provide a custom error message depending on the given condition? I'm using https://github.com/networknt/json-schema-validator, version 1.0.43

This is my JSON Schema:

{
  "$id": "https://configurations/provider.json",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Configuration",
  "type": "object",
  "properties": {
    "provider": {
      "description": "Name of the provider.",
      "enum": [
        "Provider #1",
        "Provider #2"
      ]
    },
    "configuration": {
      "$schema": "json-schema/configurations/configuration.json"
    }
  },
  "if": {
    "properties": {
      "parcsProvider": {
        "const": "Provider #1"
      }
    }
  },
  "then": {
    "required": [
      "configuration"
    ]
  },
  "else": {
    "not": {
      "required": [
        "configuration"
      ]
    }
  }
}

If the value for the provider is "Provider #1" then the configuration object is required, and if it's "Provider #2" and configuration is passed an error will occur. I want to customize that error so that the response is the same as it is now but with a custom message like "Provider 2 can't have a configuration."

Current error message/response:

{
    "timestamp": "2020-11-23T12:50:56.20658+01:00",
    "message": "invalid.json.input",
    "validationErrors": [
        {
            "field": "$",
            "message": "$: should not be valid to the schema \"not\" : {\"required\":[\"configuration\"]}"
        }
    ]
}

Upvotes: 5

Views: 10058

Answers (1)

Ashutosh
Ashutosh

Reputation: 1107

I had a similar requirement to implement in one of my projects. For validation, I was using https://github.com/everit-org/json-schema.

Here is what I did

  1. Categorized all kind of errors[there must be some specific keyword] thrown by the validator
  2. Now once you have all the keys, you can easily manipulate the errors and send the custom error/response.

Below are the keys I have collected for different cases, this might help you -

MIN_LENGTH_VIOLATION = "expected minLength"
MAX_LENGTH_VIOLATION = "expected maxLength"
PATTERN_VIOLATION = "does not match pattern"
DATA_TYPE_VIOLATION = "expected type"
DEPENDENCY_VIOLATION = "is required"
FORMAT_VIOLATION_OR_ENUM_VALIDATION_VIOLATION = "is not a valid"
MANDATORY_FIELD_VIOLATION_OR_CONDITIONAL_VIOLATION = "required key"
NUMBER_IS_LESS_THAN_VIOLATION = "is not greater or equal to"
NUMBER_IS_GREATER_THAN_VIOLATION = "is not less or equal"
EXCLUSIVE_NUMBER_IS_GREATER_THAN_VIOLATION = "is not less than"
EXCLUSIVE_NUMBER_IS_LESS_THAN_VIOLATION = "is not greater than"
MULTIPLE_OF_VIOLATION = "is not a multiple"

Sample Code -

 private static void validate(JSONObject request) {
    try {
        // Schema, that might be fetched dynamically from some data source
        JSONObject schema = new JSONObject();
        Schema loadedSchema = SchemaLoader.load(schema);
        loadedSchema.validate(request);
    } catch (ValidationException ve) {
        List<String> allErrorMessages = ve.getAllMessages();
        List<String> mandatoryFields = parseMandatoryField(allErrorMessages);
        if (CollectionUtils.isNotEmpty(mandatoryFields)) {
            throw new MandFieldMissingExp(mandatoryFields);
        } else {
            List<String> invalidFields = parseInvalids(allErrorMessages);
            throw new InvalidFieldExp(invalidFields);
        }
    }
}

private static List<String> parseMandatoryField(List<String> validationExceptionMessages) {
    Set<String> mandatoryListSet = new HashSet<>();
    validationExceptionMessages.forEach(errorMessage -> {
        if (StringUtils.containsAny(errorMessage, MANDATORY_FIELD_VIOLATION_OR_CONDITIONAL_VIOLATION, DEPENDENCY_VIOLATION)) {
            mandatoryListSet.add(StringUtils.substring(errorMessage, errorMessage.indexOf('[') + 1, errorMessage.indexOf(']')));
        }
    });
    return new ArrayList<>(mandatoryListSet);
}

private static List<String> parseInvalids(List<String> validationExceptionMessages) {
    Set<String> invalidParamsSet = new HashSet<>();
    validationExceptionMessages.forEach(errorMessage -> {
        if (StringUtils.containsAny(errorMessage, MIN_LENGTH_VIOLATION, MAX_LENGTH_VIOLATION, PATTERN_VIOLATION,
                FORMAT_VIOLATION_OR_ENUM_VALIDATION_VIOLATION, DATA_TYPE_VIOLATION, NUMBER_IS_LESS_THAN_VIOLATION,
                MULTIPLE_OF_VIOLATION, EXCLUSIVE_NUMBER_IS_GREATER_THAN_VIOLATION, NUMBER_IS_GREATER_THAN_VIOLATION
                , EXCLUSIVE_NUMBER_IS_LESS_THAN_VIOLATION)) {
            invalidParamsSet.add(StringUtils.substring(errorMessage, errorMessage.indexOf('/') + 1, errorMessage.indexOf(':')));
        }
    });
    return new ArrayList<>(invalidParamsSet);
}

Hope it helps

Upvotes: 3

Related Questions