Foundations of a building

Building Strong Foundations: Leveraging JSON Schema for Comprehensive REST API Documentation and Testing

JSON Schema is a very helpful object definition language for implementing well-documented REST APIs. It is useful for documenting and validating JSON objects, and we will learn how to improve our API responses using it.

Although there are other alternatives available, such as TypeSchema, OpenAPI, or JTD (JSON Type Definition) —which I encourage you to explore—, we will focus on JSON Schema because of my personal experience working with it.

There are several benefits to using declarative JSON languages:

  • They provide a clear description of the data format.
  • They give developers a specification of the expected format of the response.
  • They generate human-readable documentation.
  • They make future technology migrations easier.

Where should we start?

To start learning about JSON Schema, I recommend taking a look at the official “getting started” documentation. This short introductory guide will teach you the basics of this specification.

Additionally, I suggest keeping the JSON Schema reference documentation close by in case you need further assistance.

Generating schemas

Considering you know the basics of the specification, let’s begin the generation of schemas for our API responses.

Considering that this specification is very comprehensive, it can be both helpful and complicated. To expedite this task, we can utilize some generation tools. I’ve used it before and recommend the Liquid Technologies JSON Schema generator, but you can use any of the alternatives listed here.

These tools can generate JSON Schemas based on an example JSON object, so you don’t need to write the schema from scratch.

Follow these steps:

  1. Write an example JSON response for your REST API endpoint.
  2. Use the generation tool to create a schema based on your example.
  3. Review the generated schema and fix any errors (nullable values and minor issues specific to your use case may be missing).
  4. If you make various changes to the schema generated in step 2, it’s recommended to validate the new schema syntax using a validation tool. You can use JSON Schema Validator or any of the tools listed here.

For example, if we have the following JSON object:

{
	"user_id": 285293,
	"email_address": "[email protected]",
	"first_name": "John",
	"last_name": "Doe",
	"roles": [ 
		"administrator", 
		"user" 
	],
	"phone_number": "(XXX)XXX-XXXX"
}

The final schema will be the following:

{
  "$schema": "<http://json-schema.org/draft-07/schema#>",
  "type": "object",
  "properties": {
    "user_id": {
      "type": "integer"
    },
    "email_address": {
      "type": "string"
    },
    "first_name": {
      "type": "string"
    },
    "last_name": {
      "type": "string"
    },
    "roles": {
      "type": "array",
    },
    "phone_number": {
      "type": [ 
				"string", 
				"null"
			]
    }
  },
  "required": [
    "user_id",
    "email_address",
    "first_name",
    "last_name",
    "roles",
    "phone_number"
  ]
}

It is worth noting that this tool can also be very helpful if you need to document the JSON document expected as the body of your POST requests.

Integration with PHP

To implement the validation of your endpoint responses using PHPUnit, you may have a schema validator.

On PHP, I recommend using Opis JSON Schema, this is a well-documented package and supports the latest specification (at this moment, it’s draft-2020-12).

To install it, we just need to run:

composer require opis/json-schema

Once we have the package installed, we’re able to start the validation of our responses.

To do that, let’s create a new test.

use Opis\\JsonSchema\\Validator
use Opis\\JsonSchema\\Exceptions\\SchemaException;

...

public function userSchemaTest() {
	try {
		$endpointUrl = "<https://example.42mate.com/api/users/>";
		$response = $this->getJson($endpointUrl);
		$schema = <<<'JSON'
		{
		  "$schema": "<http://json-schema.org/draft-07/schema#>",
		  "type": "object",
		  "properties": {
		    "user_id": {
		      "type": "integer"
		    },
		    "email_address": {
		      "type": "string"
		    },
		    "first_name": {
		      "type": "string"
		    },
		    "last_name": {
		      "type": "string"
		    },
		    "roles": {
		      "type": "array",
		    },
		    "phone_number": {
		      "type": [ 
						"string", 
						"null"
					]
		    }
		  },
		  "required": [
		    "user_id",
		    "email_address",
		    "first_name",
		    "last_name",
		    "roles",
		    "phone_number"
		  ]
		}
		JSON;
		// Now, let's assert the schema is valid
		// for that, we'll use the opis/json-schema validate() function
		$validator = new Validator();
		$result = $validator->validate($response->json(), $schema);
		$this->assertTrue($result->isValid());
	} catch (SchemaException $e) {
		$this->fail($e->getMessage());
	}
}

You can have more information about the implementation of the Validator from opis/json-schema on the documentation.

Bonus: conversion between JSON Schema and OpenAPI

Many APIs use Swagger to document their existing endpoints, typically through OpenAPI annotations. If this applies to you, or if you have response specifications written in OpenAPI, you can convert from OpenAPI to JSON Schema by using instrumenta/openapi2jsonschema.

However, if you want to do the opposite, note that OpenAPI supports JSON Schema.

1 thought on “Building Strong Foundations: Leveraging JSON Schema for Comprehensive REST API Documentation and Testing

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.