/** * @file * * @brief Demonstrates validation against a manually constructed schema. * * This example demonstrates the construction and composition of a Schema object * using manually created Constraint objects. The following Constraint classes * are used: * - EnumConstraint * - MaxLengthConstraint * - MinimumConstraint * - MinLengthConstraint * - PropertiesConstraint * - RequiredConstraint * - TypeConstraint * * The MinimumConstraint class provides support for the exclusiveMinimum and * minimum keywords in JSON Schema. And the PropertiesConstraint class provides * support for the properties, patternProperties, and additionalProperties * keywords. * * This is the JSON Schema representation of the Schema that will be created: * * { * "properties": { * "category": { * "enum": [ * "album", * "book", * "other", * "video" * ] * }, * "description": { * "type": "string" * }, * "price": { * "exclusiveMinimum": true, * "minimum": 0.0, * "type": "number" * }, * "title": { * "maxLength": 200, * "minLength": 1, * "type": "string" * } * }, * "required": [ * "category", * "price", * "title" * ], * "type": "object" * } * */ #include #include #include #include #include #include #include #include #include using std::cerr; using std::endl; using valijson::Schema; using valijson::Subschema; using valijson::Validator; using valijson::ValidationResults; using valijson::adapters::RapidJsonAdapter; using valijson::adapters::RapidJsonFrozenValue; using valijson::constraints::EnumConstraint; using valijson::constraints::MaxLengthConstraint; using valijson::constraints::MinimumConstraint; using valijson::constraints::MinLengthConstraint; using valijson::constraints::PropertiesConstraint; using valijson::constraints::RequiredConstraint; using valijson::constraints::TypeConstraint; void addPropertiesConstraint(Schema &schema) { PropertiesConstraint propertiesConstraint; { // Prepare an enum constraint requires a document to be equal to at // least one of a set of possible values EnumConstraint constraint; constraint.addValue(RapidJsonFrozenValue("album")); constraint.addValue(RapidJsonFrozenValue("book")); constraint.addValue(RapidJsonFrozenValue("other")); constraint.addValue(RapidJsonFrozenValue("video")); // Create a subschema, owned by the root schema, with a constraint const Subschema *subschema = schema.createSubschema(); schema.addConstraintToSubschema(constraint, subschema); // Include subschema in properties constraint propertiesConstraint.addPropertySubschema("category", subschema); } { // Create a child schema for the 'description' property that requires // a string, but does not enforce any length constraints. const Subschema *subschema = schema.createSubschema(); TypeConstraint typeConstraint; typeConstraint.addNamedType(TypeConstraint::kString); schema.addConstraintToSubschema(typeConstraint, subschema); // Include subschema in properties constraint propertiesConstraint.addPropertySubschema("description", subschema); } { // Create a child schema for the 'price' property, that requires a // number with a value greater than zero. const Subschema *subschema = schema.createSubschema(); MinimumConstraint minimumConstraint; minimumConstraint.setMinimum(0.0); minimumConstraint.setExclusiveMinimum(true); schema.addConstraintToSubschema(minimumConstraint, subschema); TypeConstraint typeConstraint; typeConstraint.addNamedType(TypeConstraint::kNumber); schema.addConstraintToSubschema(typeConstraint, subschema); // Include subschema in properties constraint propertiesConstraint.addPropertySubschema("price", subschema); } { // Create a child schema for the 'title' property that requires a string // that is between 1 and 200 characters in length. const Subschema *subschema = schema.createSubschema(); MaxLengthConstraint maxLengthConstraint; maxLengthConstraint.setMaxLength(200); schema.addConstraintToSubschema(maxLengthConstraint, subschema); MinLengthConstraint minLengthConstraint; minLengthConstraint.setMinLength(0); schema.addConstraintToSubschema(minLengthConstraint, subschema); TypeConstraint typeConstraint; typeConstraint.addNamedType(TypeConstraint::kString); schema.addConstraintToSubschema(typeConstraint, subschema); // Include subschema in properties constraint propertiesConstraint.addPropertySubschema("title", subschema); } // Add a PropertiesConstraint to the root schema schema.addConstraint(propertiesConstraint); } void addRequiredConstraint(Schema &schema) { // Add a RequiredConstraint to the schema, specifying that the category, // price, and title properties must be present. RequiredConstraint constraint; constraint.addRequiredProperty("category"); constraint.addRequiredProperty("price"); constraint.addRequiredProperty("title"); schema.addConstraint(constraint); } void addTypeConstraint(Schema &schema) { // Add a TypeConstraint to the schema, specifying that the root of the // document must be an object. TypeConstraint typeConstraint; typeConstraint.addNamedType(TypeConstraint::kObject); schema.addConstraint(typeConstraint); } int main(int argc, char *argv[]) { if (argc != 2) { cerr << "Usage:" << endl; cerr << " ./custom_schema " << endl; cerr << endl; return 1; } // Load the document that is to be validated rapidjson::Document targetDocument; if (!valijson::utils::loadDocument(argv[1], targetDocument)) { cerr << "Failed to load target document." << endl; return 1; } // Populate a schema Schema schema; addPropertiesConstraint(schema); addRequiredConstraint(schema); addTypeConstraint(schema); // Perform validation Validator validator; ValidationResults results; RapidJsonAdapter targetDocumentAdapter(targetDocument); if (!validator.validate(schema, targetDocumentAdapter, &results)) { std::cerr << "Validation failed." << endl; ValidationResults::Error error; unsigned int errorNum = 1; while (results.popError(error)) { cerr << "Error #" << errorNum << std::endl; cerr << " "; for (const std::string &contextElement : error.context) { cerr << contextElement << " "; } cerr << endl; cerr << " - " << error.description << endl; ++errorNum; } return 1; } return 0; }