← All articles
MuleSoft · Validation

Mule 3.x: JSON Schema Validation with a Dynamic Schema Location

Mule 3.x included a JSON Schema Validator for checking an incoming JSON payload against a referenced schema. The standard configuration works well when the schema location is known at design time.



<json:validate-schema schemaLocation="http://my.site/schemas/some_schema.json" doc:name="Validate Json Schema"/>
View original Gist ↗

The challenge in this use case was that the schema location needed to be determined dynamically—for example, retrieved from a database and stored in a flow variable.



<set-variable name="dynamicSchemaLocation" value="http://my.site/schemas/some_schema.json" doc:name="Variable Dynamic Schema Location" />
View original Gist ↗

Attempting to pass that runtime value directly to the validator's schemaLocation attribute caused the application deployment to fail in the Mule version used for this article.



<json:validate-schema schemaLocation="#[flowVars.dynamicSchemaLocation]" doc:name="Validate Json Schema"/>
View original Gist ↗

Workaround

The solution was to move validation into a custom processor:

  1. Read the schema location from the flow variable.
  2. Create an instance of Mule's JSON Schema Validator.
  3. Supply the resolved schema location programmatically.
  4. Invoke the validator's 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;
	}


}
View original Gist ↗


<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" />
View original Gist ↗

Version context: This is a Mule 3.x implementation. Mule 4 has a different runtime, SDK, expression model, and validation tooling, so do not carry this custom-processor approach forward without checking the current platform capabilities first.

Design Considerations

Dynamic schema selection can be useful when a single flow handles multiple payload contracts, but it also introduces operational concerns. Schema locations should be controlled, validated, and ideally cached rather than accepting arbitrary external paths at runtime.

Takeaway

When a framework component exposes only a static configuration value, a small programmatic wrapper can provide the needed runtime flexibility. The trade-off is tighter coupling to platform internals, so the approach should be isolated and revisited during runtime upgrades.

CONTINUE READING

Explore closely related architecture, integration and implementation topics.