Testing APIs With Fastify, JSON Schema
This is post 3, from a 3 part series, where I will demonstrate how to setup a node.js based api, with an external JSON schema/swagger specification. I will be using fastify, which supports swagger/json-schema out of the box.
This series of posts includes:
1. Building APIs with Fastify, JSON Schema
2. Documentating APIs with fastify, JSON Schema
3. Testing APis with Fastify, JSON Schema
The source code for this post can be found here:
https://github.com/AndrewKeig/fastify-api-with-json-schema
Here you will find a postman file, to run the endpoints:
https://github.com/AndrewKeig/fastify-api-with-json-schema/blob/master/postman.json
Testing swagger authentication
Testing swagger authentication is straight forward, our swagger document, has the following security definition, which defines a token
be present in the headers
, its of type apikey
:
Full swagger document can be found here: src/swagger.json
"securityDefinitions" : {
"bearerAuth" : {
"type" : "apiKey",
"in" : "header",
"name" : "token"
}
}
The below test sends an invalid token
inside the request header, which returns the correct response, 401 unauthenticated
.
const swaggerFixtures = require("swagger-fixtures");
const app = require("../../src/app");
const swagger = require("../../src/swagger.json");
describe("Authenticate", () => {
afterAll(() => {
app.close();
});
describe("Authenticate token", () => {
test("should reject if token invalid", async () => {
const payload = swaggerFixtures(swagger, "User");
const response = await app.inject({
method: "GET",
url: "/v1/user/12345",
payload,
headers: { token: "12345" },
});
const parsed = JSON.parse(response.payload);
const expectedMessage = "Unauthorized";
expect(response.statusCode).toBe(401);
expect(parsed.message).toBe(expectedMessage);
});
});
});
Testing swagger validation rules
Testing our validation rules as defined in our swagger document, requires us to provide a request body
, for this we are using swagger-fixtures
, a modules which scans the swagger document for swagger examples, and builds a JSON payload from these examples. If you prefer you can simply hard code a request body.
Thus test sends in a valid fixture and valid token in the header, so our test passes with a 201
response.
const swaggerFixtures = require("swagger-fixtures");
const app = require("../../src/app");
const swagger = require("../../src/swagger.json");
describe("Add User", () => {
afterAll(() => {
app.close();
});
describe("Add a user success", () => {
test("should return valid response", async () => {
const payload = swaggerFixtures(swagger, "User");
const response = await app.inject({
method: "POST",
url: "/v1/user",
payload,
headers: { token: "1111-2222-3333-444" },
});
const parsed = JSON.parse(response.payload);
const expectedMessage = "User added successfully";
expect(response.statusCode).toBe(201);
expect(parsed.message).toBe(expectedMessage);
});
});
});
In this test we invalidate the email
and get a 422
response.
const swaggerFixtures = require("swagger-fixtures");
const app = require("../../src/app");
const swagger = require("../../src/swagger.json");
describe("Add User", () => {
afterAll(() => {
app.close();
});
describe("Add a user failure", () => {
test("should return a validation error", async () => {
const payload = swaggerFixtures(swagger, "User");
// invalidate email
payload.email = "andrew@email.com";
const response = await app.inject({
method: "POST",
url: "/v1/user",
payload,
headers: { token: "1111-2222-3333-444" },
});
const parsed = JSON.parse(response.payload);
const expectedMessage = 'Email should match format \\"email\\"';
expect(response.statusCode).toBe(422);
expect(parsed.message).toBe(expectedMessage);
});
});
});
You can use this pattern to build up a test suite, which test all of your validation rules, for all your endpoints and models.