zod-api-validator
v0.0.7
Published
Zod API Validator enables you to rapidly test API's to ensure the desired output matches a defined schema. To use the package you define a config file that lists all of the endpoint urls that you want to test, along with the zod schema that outlines th
Downloads
2
Readme
🤖 Zod API Validator (ZAV)
Zod API Validator enables you to rapidly test API's to ensure the desired output matches a defined schema. To use the package you define a config file that lists all of the endpoint urls that you want to test, along with the zod schema that outlines the desired response schema. The validator can be run from the CLI for local development, or it can be hosted as an independent application which enables support for CI/CD pipelines.
🚧 Roadmap
- Add support for request body/payload (Currently only supports GET requests)
- Full TypeScript support
- Add support for cjs (commonjs)
⚙️ Getting Started
Prerequisites
You must have Zod installed into your app. This is so you can defined Zod schemas in your repo.
$ npm install zod
Setup
- Install the package into your app
$ npm install zod-api-validator
- Create a new file in your repo called
zav.config.js
with the following contents:
zav.config.js
import { z } from 'zod';
/**
* An array of endpoint objects. Each endpoint object should have the following properties:
* method - The method to use on the request as a string (GET/POST/PUT/PATCH/DELTE). e.g "GET"
* url - The http/https endpoint to call as a string. e.g "http://localhost:5000/api/test"
* schema - A Zod schema object. e.g z.object({ name: z.string(), age: z.number() })
*/
const endpoints = [
// { method: 'GET', url: 'http://127.0.0.1:5000/api/test', schema: userSchema },
];
const config = {
configName: 'my-first-config',
endpoints,
}
export default config;
- Create a Zod schema for the endpoint you want to test
UserSchema.zav.js
export const userSchema = z.object({
name: z.string(),
email: z.string().min(20, 'Must be more than 20 chars').email('Invalid email'),
age: z.number().min(18, 'You must be over 18'),
})
- Add your endpoint and schema to the config file
zav.config.js
import { z } from 'zod';
import { userSchema } from './UserSchema';
/**
* An array of endpoint objects. Each endpoint object should have the following properties:
* method - The method to use on the request as a string (GET/POST/PUT/PATCH/DELTE). e.g "GET"
* url - The http/https endpoint to call as a string. e.g "http://localhost:5000/api/test"
* schema - A Zod schema object. e.g z.object({ name: z.string(), age: z.number() })
*/
const endpoints = [
{ method: 'GET', url: 'http://127.0.0.1:5000/api/test', schema: userSchema },
];
const config = {
configName: 'my-first-config',
endpoints,
}
export default config;
- That's it! You are now setup to run the validator.
Running the Validator
The validator has a few different methods of running. Which method you choose may come down to your use case.
CLI
The first method is via the CLI. This is better suited to those who are developing locally or designing the schemas that they wish to use for the tests. The CLI commands come bundled with the package and do not require any extra setup.
To run from the CLI, run the following command in the root of your project.
$ zav
In your terminal you will see an output in this format
Valid response from API:
***** my-first-config (zav.config.js) *****
GET http://localhost:5000/api/user - VALID
Invalid response from API:
***** my-first-config (zav.config.js) *****
GET http://localhost:5000/api/user - INVALID
name: Expected string, received boolean,
email: Must be more than 20 chars,
email: Invalid email
Server Application
The validator can also be hosted as an independent application. This is beneficial when you wish to test deployed API's or integrate the validator into a CI/CD pipeline.
You can run the server application with the following command:
$ zav-server
By default the server will be run on port 4000.
The application uses dotenv, so the port can be changed using PORT
env var.
Once the server is running you can navigate to http://127.0.0,1:4000. Here you can find a simple GUI that outputs the results of the validator. Each time you refresh the page the validator will run and send a request to all of the endpoints in the configs.
Targeting specific config files
Sometimes you may only want to test a specific config or a couple of specific configs. You can do this via query params. There are 2 supported query params:
| Parameter | Value | Example url |
|---------------|------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
| config | The configName
value defined in the zav config file you wish to test | http://127.0.0.1:4000?config=my-first-config |
| configs | A comma separated list of configName
values | http://127.0.0.1:4000?configs=my-first-config,another-config,my-app |
When using these query params, only the endpoints listed in the config files will be tested.
CI/CD Pipeline Integration
The validator can be integrated into your workflow or pipeline to help ensure API endpoints are working as expected.
When the server is running it also exposes the following endpoint: http://127.0.0.1:4000/pipeline
When navigating to this url the configuration files will be loaded and tested in the same way as if you were running from the CLI or GUI. The difference being that it will output the raw response from the console.
The pipeline endpoint also supports the query parameters for targeting specific config files.
Inside the package bundle you will find an example script called pipeline-script.sh
. This is the command that can be
run as part of your pipeline.
pipeline-script.sh
if [[ $ZavPipelineUrl == "" ]]; then
echo "'ZavPipelineUrl' environment variable is not set"
exit 1;
fi
text=$(curl -s "$ZavPipelineUrl")
string="PIPELINE FAILED"
if [[ $text == *"$string"* ]]; then
echo "$text"
echo "Zod API Validator finished with errors"
exit 1;
else
echo "$text"
echo "Zod API Validator finished successfully"
exit 0;
fi
The script checks for an environment variable called ZavPipelineUrl
, this should be the full url of the hosted
zod-api-validator application. For example, ZavPipelineUrl=https://my-zav-app.com/pipeline
Then inside your CI/CD you can add a step for calling the validator. Below is an example in GitLab.
.gitlab-ci.yml
image: docker:stable
stages:
- test-api
run-zav:
stage: test-api
before_script:
- apk add --update curl && rm -rf /var/cache/apk/*
script:
- |
if [[ $ZavPipelineUrl == "" ]]; then
echo "'ZavPipelineUrl' environment variable is not set"
exit 1;
fi
text=$(curl -s "$ZavPipelineUrl")
string="PIPELINE FAILED"
if [[ $text == *"$string"* ]]; then
echo "$text"
echo "Zod API Validator finished with errors"
exit 1;
else
echo "$text"
echo "Zod API Validator finished successfully"
exit 0;
fi
The script will finish with an exit code 0 if it passes, or an exit code 1 if it fails.
Slack Integration
You can use Slack Webhooks to log all messages from the zod-api-validator to a specific channel. This can be especially useful when trying to keep a full log of each run, and live monitoring. The Slack Webhook will be fired each time the pipeline runs, and each time the validator is run from the GUI.
To setup Slack Webhooks, you simply need to create an environment variable with the webhook URL. The validator will automatically detect the environment variable and attempt to log to Slack when it is found.
ZAV_SLACK_WEBHOOK_URL=XXXX
Scheduled Cron Job
The validator can also be run on a schedule. This can eb especially useful once you have the Slack integration set up,
as it will automate the tests and all results can be tracked and logged in Slack. You can set up a scheduled cron by
setting the ZAV_CRON
environment variable.
ZAV_CRON=1h
The above example will run the validator every hour. The currently supported periods are:
| Variable Value | Period | |----------------|-----------------------| | 1h | Every hour | | 2h | Every 2 hours | | 3h | Every 3 hours | | 4h | Every 4 hours | | 6h | Every 6 hours | | 1d | Every day at midnight |
The cron will only be initialised if this variable is set. If the variable is not set when the server runs, then the cron will not be scheduled.
Example Use Case
It is common to see front-end and back-end applications in different repositories and this often leads to API schemas being defined twice. The front-end will be making calls to the API endpoints and expect an exact schema, if these become misaligned it can cause the front-end application to break.
When working in larger teams, it is much harder to keep track of all the changes happening to the back-end API schema and ensure that all of these changes have been reflected or considered on the front-end.
The validator can help ensure that there are no unexpected changes to existing endpoints, or ensure that new endpoints match the exact schema implemented on the front-end.
The validator can be implemented at various stages of a project. In either case the first step is to create a new repo with zod and zod-api-validator installed.
For an existing project, the front-end will have defined a full set of DTO's that it uses to interact with the API. In this case the first step would be to create zod schemas for each of the front-end DTO's used in the front-end application. Then inside the zav.config files we can list all of the endpoints and the schemas related to them.
The next step is host the app.
Once hosted we can navigate to the hosted url and we should be able to see all of the endpoints are responding as valid. Then we can integrate the pipeline script with the back-end repository. The pipeline script can run on each pull request commit. This now means that if any endpoints change and they have not been updated in the validator schemas, the pipeline will fail. This prevents code from being merged/deployed that has not been updated yet.