WordPress and JSON Schemas Noob Notes

Learning the basics about validating inputs using JSON Schemas in WordPress REST API plugins.

I was on this journey to make a complex Gutenberg block, but tripped up a lot because I’d forgotten so much WordPress programming. To get used to it again, I went through the Plugin Handbook, and built a “kitchen sink” plugin, which is just a bunch of play versions of the different plugin features. Along the way, I found out that the REST API uses JSON Schemas for validation. This post is links out to resources about this feature in WordPress.

JSON schemas are JSON documents that describe other JSON documents in a rigorous fashion. It’s a schema description system, and useful for validation or sanitization of inputs and outputs, and formal documentation of both external and internal data structures.

The schemas are explained in the Handbook under Schemas, and also in Routes & Endpoints.

I was noticing that by putting the validation code up in the schema, I could save a few lines of code, and keep the code tidier:

class Example2 {
    private $data;

    public function __construct( string $namespace, string $path, callable $permissions, array $data ) {
        $this->data = $data;
        register_rest_route( $namespace, $path, [
            'methods'  => WP_REST_Server::READABLE,
            'permissions_callback' => $permissions,
            'callback' => [ $this, 'get' ],
            'args' => [ // validation schema 
                'order' => [ // an arg after the ? in the URL
                    'description' => 'sorting for the list',
                    'type' => 'string',
                    'enum' => [ 'asc', 'desc' ]   // must match these values
                ]
            ]
        ]);
        register_rest_route( $namespace, $path.'(?P<id>[\d]+)', [
            'methods'  => WP_REST_Server::READABLE,
            'permissions_callback' => $permissions,
            'callback' => [ $this, 'get_one_2' ],
            'args' => [ // validation schema
                'id' => [ // an arg pulled from the URI
                    'description' => 'the index',
                    'type' => 'int',
                    'required' => true,
                    'validate_callback' => function( $value, $request, $param ) {
                        if ((0 <= $value) and ($value < count($this->data))) return true;
                        else return false;
                    },
                    // the validation callback is run before the main callback is called
                    'sanitize_callback' => function( $value, $request, $param ) {
                        return (int)$value;
                    }
                    // this sanitization step doesn't really do anything.
                ]
            ]
        ]);
    }

    public function get_one_2( $request ) {
        // This version relies on the validation and sanitization callbacks 
        // in the schema.
        return rest_ensure_response( $this->data[$request['id']] );
    }

    public function get( $request ) {
        // This relies on the validation schema
        if ($request['order'] == 'asc') sort($this->data);
        if ($request['order'] == 'desc') rsort($this->data);
        return rest_ensure_response( $this->data );
    }
}

You’re just going to have to imagine the old validation code. It was slightly longer than the validator functions in the code. So there’s a small savings in code, and a nice refactoring of concerns, so the controllers are leaner. Most importantly, it’s one less thing to think about!

Also, the schema becomes part of the API, and allows for a kind of rudimentary documentation for API consumers.

More Resources

JSON Schema has the standard tutorial for JSON schemas.

Timothy Jacobs has a great article, JSON Schema and the WP REST API, that gets into how schemas work, the deficiencies in WordPress’ implementation, and presents a more standard implementation based on a JSON Schema validation library by JSON Rainbow, json-schema.

Jacobs’ library will replace the WordPress stock validator, and allow more strict validation of inputs and outputs.