API validation with JSON Schema

Employing JSON Schema is an easy and straightforward way to validate input to your APIs - learn below how it can be enabled for Zato services in one line of code.

Preparing a schema

Supposing that our service needs two parameters:

  • name (string)
  • pub_year (integer)

This is how a schema representing them may look like - let's save it in a file called myschema.json.

{
  "type": "object",
  "required": ["name", "pub_year"],
  "properties": {
    "name":  {"type" : "string"},
    "pub_year": {"type" : "number"}
  }
}

This is as simple as it can get - we list our parameters and for each one, we also say of what datatype they are.

Note that a JSON Schema may be of arbitrary complexity to express any kind of business needs. It is also possible to split bigger schemas into reusable pieces, ready for inclusion in more than one place.

Uploading the schema

Each server has a directory called config/repo/schema/json - this is where the schema needs to be uploaded.

For instance, if path to a server is /home/zato/env/server1 then the full path will be /home/zato/env/server1/config/repo/schema/json.

Save myschema.json to this directory and restart your server before continuing to the next step.

Configuring a service

To make use of the prepared schema, a service uses an attribute appropriately called schema, as below.

# -*- coding: utf-8 -*-

from __future__ import absolute_import, division, print_function, unicode_literals

# Zato
from zato.server.service import Service

class MyService(Service):

    # Require JSON Schema validation
    schema = 'myschema.json'

    def handle(self):

        # If we are here, it means that the input schema validation succeeded
        self.logger.info("My request: %s", self.request.payload)

Note that the value of this attribute can be either relative or absolute. If it is relative, it is in relation to the main directory (config/repo/schema/json). If it is an absolute one, it must be a full path to the schema file in the filesystem.

Schema validation in runtime

You do not need to do anything else for schema validation to work, let's observe it.

As expected, on invalid input we get an error:

$ curl localhost:17010/schema/check -d '{"user_id":123}' ; echo
{"zato_env":
  {"result": "ZATO_ERROR",
   "cid": "0ee199609d5020d7cb8ca924",
   "details":
     {"is_ok": false,
      "cid": "0ee199609d5020d7cb8ca924",
      "message": "Invalid request"
  }}}
$

Whereas with correct data on input a message is stored in a log file:

INFO - My request: {'name':'The Garden of Cyrus', 'pub_year':1658}

Dashboard options

Sometimes it is handy to be able to disable input validation on demand, without redeployment of code. On the other hand, it is at times convenient to return more details than "Invalid request" alone.

This is exactly what can be done in web-admin, for each service separately:

Summary

That is all - you have just created a schema and enabled it for your service. Zato picked it up, started to enforce its definitions in runtime, and the whole of it took just a single line of code. Moreover, you can dynamically change the way it is used without making any updates to the source code.