Type systems are now the rage in APIs. GraphQL and gRPC fans boast about their built-in systems. There are many options available for REST users, but JSON Schema appears to be the most popular.
JSON Schema can be used to create metadata for JSON. We have written about JSON Schema’s ability to simplify contract testing. JSON Schema also adds non-invasive hypermedia controls to existing APIs . JSON Schema is most compatible with OpenAPI so it can also be used to create meaningful and beautiful documentation .
Let’s now talk about validating API request. This is another chapter taken from the book. To get the most recent version from Leanpub, you can download this chapter. Existing customers should have received an email regarding it.
An API client attempts to perform an operation, such as creating a REST resource or triggering an RPC procedure. There are often validation rules that must be considered when an API client attempts to perform an operation (creating a REST resource, triggering an RPC procedure, etc.). You should consider the following: name must not exceed 20 characters, mail must contain a valid email address, date must contain a valid ISO 8601 year, and the home or mobile phone number must be entered in order to send a text message.
These rules can be found in two places: the server or the client. Because it gives the user immediate feedback, client-side validation is extremely important. This could be done depending on the UI/UX design of the client application. It might include making invalid boxes red and scrolling the user to the problem. Show basic alert boxes or disabling submit until the local data is good.
This functionality can be achieved by reproducing server-side validation on the client-side. Avoid this at all cost.
Client developers often read through the API documentation and take note of important validation rules before writing code to implement those rules. If the code finds the data valid, it will send it to the server on an event (probably on submit), and hopefully the server will also agree.
This approach seems intuitive at first. Frontend applications need immediate feedback without the need to query the server about validity. This approach is not scalable and can’t handle even the smallest changes in functionality. Clients struggle to keep up with the API’s changes as business requirements change. Rules can be added, deleted, or modified for the API. Although it is not appropriate for the API development team to change things randomly, there are always some changes. Variable Versioning Strategies for APIs aside. Even the most cautious API developers can make unexpectedly disruptive changes when it comes to validation.
One simple example is the name string, which has a maximum length of 20 characters. The API implements the change after receiving requests from the business for an increase in the maximum length to 40 characters. (It’s still and not how names work but Twitter did this.
The API developers meet up and agree that making validation rules more strict cannot be considered breaking as all requests will continue to function. They deploy the change with a maximum length of 40 characters. One client-app then deploys an update to match the new value, increasing the validation level to 40. Everyone is happy, despite the fact that different client applications have the same hardcoded maximum length of 20 characters.
One user takes advantage of the opportunity to create a long name and goes well beyond the limit of 20 characters. They later try to edit another field in the iOS app, but their name is reduced to just 20 characters because the input field won’t take more than that. They are confused and grab their friend’s phone to try it. Android’s application is a bit different. The form fills in all 40 characters, but the client-side validation shows an error after the form is submitted. This application does not allow users to update their user profiles without truncating the name.
Good APIs offer a copy in a programmatically-accessible format of the contracts. It is important that validation rules are written somewhere and not only in the backend code. Clients will be much more secure if they can see the validation rules.
JSON generator can be very straightforward. It simply asks for information about which fields may exist, whether they are required or not, and what data format they use. You can add validation rules to this basic premise and human-readable information. The metadata is stored in and.json files. This might look something like this:
Although there is a lot of information here, most of it should be easily understood by the human eye. Listing properties by name, assigning them data types, setting maxLength to the name as shown in the example, and adding human-readable descriptions. Some examples were also included for fun.
The $schema Key, which points to the current draft of JSON Schema, is probably the most confusing. It is crucial to know which draft you are validating against, since a JSON Schema file created for Draft 07 can’t be validated using a Draft 06 validator or lower. JSON Schema doesn’t change crap randomly, so most JSON Schema tools are quite reliable.
If you enter your date of birth incorrectly, another validation rule may be activated.
The schema URL is available to API clients so they can download it. Simply make a GET request at the URL. These are stored on CDNs like S3 with CloudFlare. These files may also have cache headers, so ensure your HTTP client is aware of how to deal with them.
For the sake of keeping the example short, the actual JSON Schema has been “downloaded” from http://example.com/schemas/user.json and put into a local file. This is not how you would normally do it, but we’ll explain why in a moment.
To wrap the validation logic in a simple helper, a validation() function was created. Next, we pretend we have input. Realistically, the input would likely be pulled from a form. The meat is now, the validation and the triggering of errors.
This script should be called with the first validation succeeding, and the second failing with a variety of errors.
This may sound like gibberish at first glance, but it’s actually quite useful. How? This is how it works. JSONPointers may be a better solution. Another example, also available on Github will demonstrate how JSON Pointers can help create dynamic errors.
Unfortunately, a lot of the examples are specific to AJV. However, the concepts can be applied to any JSON Schema validater.
It is important to notice the new Ajv ( jsonPointers true ); Property, which makes return an HTMLSON Path instead dot notation stuff. Next, we can use the pointer to search the schema objects using the json-pointer package and locate the relevant property object. We now have the human-readable title and can create human-readable errors using the properties returned. Although this code may seem odd, we do support several types of error. Take a look at the following inputs.
These inputs provide us with a lot of useful human errors back that we can place into our UI to tell users that certain stuff is not good.
The JSON Schema can contain a lot of errors. It all depends on how well the schema files are and how many edge cases they cover. It’s a nice touch to include examples. This makes the message more understandable than simply saying “it should be an date”.
Instead, you could tie them back to the DOM by updating your forms visually as described earlier. This would include making invalid boxes red and scrolling the user to the problem. Show basic alert boxes or disabling the submit button until you have good local data!
JSON Schema is supposed not to cause validation hell as it was in the past. How? But how? The sample code stored the schema in the repo with the source code. This is, generally speaking, a bad idea. It was only done to simplify the example.
Simply put, if API developers modify the schema file to have maxLength 40, clients should request that change next time they request it. This will ensure things are in sync.
This is a simple explanation with a few caveats.
The URL is not versioned. This could mean that it may change. This is possible, provided they don’t set a long cache expiry. Your application could be subject to validation hell if a client application respects cache headers and the schema file contains cache headers.
It might not be too much if the cache is set for a short time, such as 5 minutes. If the change is minor, it may not matter that much. It’s not ideal to have multiple devices used to make profile changes, and then get hammered by a maxLength error. However, it’s not too bad if it works itself.