MuleSoft - JSON Schema Validation with Dynamic Schema Location (Mule 3.x)
While working on a Mule Application project, if you a planning to validate JSON payload against some JSON schema, and more importantly if you want to pass schema location dynamically, then this post will be beneficial for you.
Mule provides JSON Schema Validator as out of the box feature. From mule documentation, evaluates JSON payloads at runtime and verifies that they match a referenced JSON schema. You can match against schemas that exist in a local file or in an external URI. If the validation fails, an exception is raised with feedback about what went wrong and a reference to the original invalid payload.
<json:validate-schema schemaLocation="http://my.site/schemas/some_schema.json" doc:name="Validate Json Schema"/>
Above code works but here is the catch, in my scenario, the schema location was dynamic. Let's say the schema location is present in the database. Once the schema location value is retrieved from database, it is stored in a flow variable. For simplicity, I am creating a flow variable with hard-coded value. In actual application, the flow variable value will be the value retrieved from database.
<set-variable name="dynamicSchemaLocation" value="http://my.site/schemas/some_schema.json" doc:name="Variable Dynamic Schema Location" />
Now, if I try to use JSON schema validator as shown below, then mule application throws error and application deployment fails. Basically, we cannot pass dynamic schema location value for "schemaLocation" attribute.
<json:validate-schema schemaLocation="#[flowVars.dynamicSchemaLocation]" doc:name="Validate Json Schema"/>
Here are the steps to resolve this issue and use dynamic schema location:
- Create custom processor class
- Retrieved schema location value from flow variable
- Create instance of Mule's JSON Schema Validator class
- Invoke .validate operation
package com.mycompany;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.mule.api.MuleEvent;
import org.mule.api.MuleException;
import org.mule.api.processor.MessageProcessor;
import org.mule.module.json.validation.JsonSchemaDereferencing;
import org.mule.module.json.validation.JsonSchemaValidator;
import com.mycompany.BadRequestException;
import com.mycompany.NotFoundException;
/**
* This is custom JSON schema validation class which uses JsonSchemaValidator
* from mule framework. This class is created because JsonSchemaValidator from
* mule framework cannot evaluate schemaLocation value from flow variable.
*
* @author Sagar Chaudhari
*
*/
public class JsonSchemaValidationProcessor implements MessageProcessor {
private static final String X_FLOW_VAR_SCHEMA_LOCATION = "dynamicSchemaLocation";
private JsonSchemaDereferencing dereferencing = JsonSchemaDereferencing.CANONICAL;
private Map<String, String> schemaRedirects = new HashMap<String, String>();
private JsonSchemaValidator validator;
@Override
public MuleEvent process(MuleEvent event) throws MuleException {
String schemaLocation = event.getFlowVariable(X_FLOW_VAR_SCHEMA_LOCATION);
if (StringUtils.isBlank(schemaLocation)) {
throw new NotFoundException("schemaLocation is not configured");
}
validator = JsonSchemaValidator.builder()
.setSchemaLocation(schemaLocation)
.setDereferencing(dereferencing)
.addSchemaRedirects(schemaRedirects)
.build();
try {
validator.validate(event);
} catch (Exception e) {
throw new BadRequestException(e.getMessage());
}
return event;
}
}
<set-variable name="dynamicSchemaLocation" value="http://my.site/schemas/some_schema.json" doc:name="Variable Dynamic Schema Location" />
<!-- Before invoking this processor, make sure payload is JSON and not Object -->
<custom-processor class="com.mycompany.JsonSchemaValidationProcessor" />
Bingo! I can now provide dynamic schema location for JSON schema validation. This is one simple way to dynamically provide JSON schema location when using JSON Schema Validator. Hope this helps.