airasoul.

Testing APIs With Fastify, JSON Schema

Cover Image for 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.