Validating API requests and responses

Shift left with Postman and OpenAPI specification

There are plenty of excellent and well-established tools that help design, create and validate an OpenAPI specification. But surely it is (at least) as critical to ensuring that the API contracts are honoured by the API we are developing.

In this article: find out how you can use Postman to validate the requests and responses, catch inconsistencies early, try out the OpenAPI Request Response Validator.

What we are going to do

The goal is to validate the API behaviour at runtime, so we are going to pass headers, request and response bodies to the validator and verify the API “does what it says”, according to its OpenAPI specification.

There are several components involved:

  • the OpenAPI file (obviously)

  • your REST API (running somewhere)

  • Postman to invoke the API endpoints

  • the Validator tool running on localhost

Diagram illustrating the interaction between Postman, a REST API, and an OpenAPI validator. The Postman icon points to a REST API with OpenAPI specs and an OpenAPI Validator, linked via "http://localhost:8080". The validator shows indicators for "PASS" and "FAIL".

Why Postman

The OpenAPI Validator is a standalone application (see later) and could be used in different ways (CI, integration testing, API gateway), but the Postman integration is powerful as it helps developers validate the API locally (shift-left), catch issues early, fix them before everyone finds out 😁.

Postman Tests allow writing test scripts that run after the execution of the request: we are going to use this feature to create a script that validates the interaction with the API, using an assertion to validate the expected result.

While a Test can be defined for each request, it is also possible (and extremely useful in this case) to create the Test script at the Collection level. You have already guessed, didn’t you? Doing this the script will run after every request in the collection.

Collection Test Script

In the Collection Tests add the snippet below.

// define object
openapiRequestResponseValidation = {
    // define function
    validate: function(pm) {

        const postRequest = {
            url: 'http://localhost:8080/validate',
            method: 'POST',
            header: {'Content-Type': 'application/json'},
            body: {
            mode: 'raw',
            raw: JSON.stringify({ 
                method: pm.request.method, 
                path: pm.request.url.getPath(),
                headers: pm.request.headers,
                requestAsJson: (pm.request.body != "") ? pm.request.body.raw : null,
                responseAsJson: pm.response.text(),
                statusCode: pm.response.code
                })
            }
        };

        pm.sendRequest(postRequest, (error, response) => {
            if(error != undefined) {
                pm.expect.fail('Unexpected error ' + error);
            } else {
                var data = response.json();

                if(data.valid == false) {
                    console.log(data.errors);
                }

                pm.test("OpenAPI validation", () => {
                    pm.expect(data.valid, "Invalid request/response (check Console)").to.equal(true);
                });

            }
        });  
    }

};

// invoke function
openapiRequestResponseValidation.validate(pm);

Let’s break down what happens:

  • first, create the object openapiRequestResponseValidation that includes a single function validate .

  • the function validate performs 3 steps: it collects all data we need (headers, request, response, HTTP status), sends a POST request to the Validator and verifies the outcome.

If it goes smoothly the test passes and is marked as green.

Test passing and marked as green

OpenAPI validation

OpenAPI Request Response Validator

The openapi-request-response-validator is a SpringBoot application with a REST controller to allow Postman scripts (or other clients) to send the payload to validate. The OpenAPI file can be supplied at startup.

The outcome of the validation (together with the list of errors — if any) is returned to Postman (displayed in the Postman console) and logged by the application.

Run with Java

Copy/rename your OpenAPI specs to openapi/openapi.yaml or openapi/openapi.json and start the application:

mvn spring-boot:run

If needed you can customise the location of the OpenAPI file

mvn spring-boot:run 
  -Dspring-boot.run.arguments="--inputSpecs=/path/to/myopenapi.yaml"

Run with Docker

You can also run it on Docker


# run using default openapi/openapi.yaml or openapi/openapi.json
docker run -v $(pwd):/openapi -it --rm \
  --name openapi-request-response-validation \
    gcatanese/openapi-request-response-validation

Once the validator is running you can crack on: run the Postman requests and check the Test Results (in case of errors).

Final remarks

OpenAPI examples

A little bonus is when your Postman collection uses (i.e. request body) the examples included in the OpenAPI file. The validation can then confirm those examples match the OpenAPI specs. We all know the API evolves and the specs change but the examples can be overlooked.

Business as usual

The idea behind the tool is that developers can focus on creating the best API while the validation is performed in the background. Go on and develop, test and ship your API (the validator will not bother you if everything works as expected).

API fails, validation doesn’t

That's a perfectly valid scenario. API calls might fail (backend errors, business rules) but the OpenAPI contract is not broken. The response with the error should be documented in the OpenAPI file and will also be validated.