DEV Community

Cover image for Validate APIs using OpenAPI and IntelliJ HTTP Client
Matthias Blümel
Matthias Blümel

Posted on • Edited on

Validate APIs using OpenAPI and IntelliJ HTTP Client

Introduction

When it comes to the development of a new API, a good approach is always to define the API contract first. This can be done using OpenAPI (formerly known as Swagger). It defines the structure of the API and how to interact with it. OpenAPI uses JSON Schema to define the structure of the request and response bodies.

What's already out there?

When developing an API, it is important to validate the responses of the API. Now that we have the contract defined in an OpenAPI schema file, we can use this schema to validate the responses of the API – but how?

There are some tools out there which can validate a JSON response against a JSON schema defined in an OpenAPI schema file. One of the most popular tools for testing APIs in my social bubble is Postman. Postman is a great tool for testing APIs, but it is not OSS, it is not integrated into the IDE and some of the features I really like are behind a paywall.

So, why not use the tools we already have? I like the HTTP Client in IntelliJ IDEA a lot, because it integrates well in my favorite IDE, it uses simple text files for the definition which allows a good integration into version control systems, and compared to other tools, you can see the whole configuration and scripts in a single file.

IntelliJ HTTP Client still misses a lot of features to be a full replacement for postman, but the most important feature I was missing was the ability to validate the response against a JSON schema – until now 🥳!

HTTP Client schema check

HTTP Client schema check is a code generator to generate code for IntelliJ HTTP Client to validate responses against JSON schemas defined in OpenAPI schema files.

Its usage is simple:

  1. Define your API contract in an OpenAPI schema file.
  2. Run the code generator to generate the necessary code for IntelliJ HTTP Client.
  3. Use the generated code in your HTTP Client response handler script to validate the responses against the defined JSON schema.
  4. Profit 🎉!

Example

Let's say you have an API like the Swagger Petstore and you want to write some test for its API-Implementation.

The OpenAPI schema file petstore.yaml is your local workspace in the directory ./schema and you have podman or docker installed.

To have a consistent naming of the generated functions, the operationId and the response code are used to generate the function name. This implies, that the operationId is properly set in the OpenAPI schema file.

openapi: 3.0.2
info:
  title: Swagger Petstore - OpenAPI 3.0
  version: 1.0.19
paths:
  /pet/{petId}:
    get:
      operationId: getPetById
      parameters:
        - name: petId
          in: path
          required: true
      responses:
        "200":
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
components:
  schemas:
    Category:
      type: object
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
    Tag:
      type: object
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
    Pet:
      required:
        - name
        - photoUrls
      type: object
      properties:
        id:
          type: integer
          format: int64
          example: 10
        name:
          type: string
          example: doggie
        category:
          $ref: '#/components/schemas/Category'
        photoUrls:
          type: array
          xml:
            wrapped: true
          items:
            type: string
            xml:
              name: photoUrl
        tags:
          type: array
          xml:
            wrapped: true
          items:
            $ref: '#/components/schemas/Tag'
        status:
          type: string
          description: pet status in the store
          enum:
            - available
            - pending
            - sold
Enter fullscreen mode Exit fullscreen mode

To generate the validation code, you only need to run the generator with the path to the directory containing your OpenAPI schema file:

podman run --rm -it --security-opt="label=disable" -v $(pwd)/schema:/app/openapi registry.gitlab.com/http-client-schema-check/http-client-schema-check:latest
Enter fullscreen mode Exit fullscreen mode

This will end up with a file named validate-petstore.js in the directory ./schema which contains the generated code to validate the response of the API. All you need to do now is to import the correct function in your IntellJ HTTP Client response handler script and use it to validate the response.

GET https://petstore3.swagger.io/api/v3/pet/10
accept: application/json

> {%
    import { getPetById_200 as validate } from '../schema/validate-petstore.js'

    client.test("Request status is 200", function() {
        client.assert(response.status === 200, "Response status is not 200 but " + response.status);
    })

    client.test("Response body is valid", function() {
        client.assert(validate(response.body), "Response body is invalid: " + JSON.stringify(validate.errors))
    })
%}
Enter fullscreen mode Exit fullscreen mode

CI/CD or IntelliJ community

Thanks to the HTTP Client cli tool, you can run the HTTP Client scripts in your CI/CD pipeline or on a local container engine without purchasing a license for IntelliJ IDEA Ultimate.

If you want to run the tests on a machine which is not a workstation like in a CI/CD pipeline, you might consider building a dedicated container image for the test runs:

# tests.Containerfile
FROM registry.gitlab.com/http-client-schema-check/http-client-schema-check:latest AS generator
COPY schema/petstore.yaml /app/openapi/petstore.yaml
RUN node create-validators.js

FROM docker.io/jetbrains/intellij-http-client AS runner
COPY --from=generator /app/openapi/validate-petstore.js /workdir/schema/validate-petstore.js
COPY tests/petstore.http /workdir/tests/petstore.http
CMD ["tests/petstore.http"]
Enter fullscreen mode Exit fullscreen mode

GitLab CI

Running these images in GitLab CI require some adjustments. e.g. if you want to run them scheduled:

testimage-build:
  image:
    name: quay.io/buildah/stable:latest
  stage: test
  before_script:
    - 'echo "$CI_REGISTRY_PASSWORD" | buildah login --username "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY'
  script:
    # no expensive builds are done, skipping layer-cache
    - buildah bud
      -f "tests.Containerfile"
      -t "$CI_REGISTRY_IMAGE/tests:$CI_COMMIT_SHORT_SHA"
      .
    - buildah push "$CI_REGISTRY_IMAGE/tests:$CI_COMMIT_SHORT_SHA"

testimage-run:
  image:
    name: "$CI_REGISTRY_IMAGE/tests:$CI_COMMIT_SHORT_SHA"
    entrypoint: [""]
  script:
    - java $IJHTTP_JAVA_OPTS -cp "/intellij-http-client/*" "com.intellij.httpClient.cli.HttpClientMain" /workdir/tests/petstore.http --report
  artifacts:
    reports:
      junit: reports/report.xml
  needs:
    - job: testimage-build

Enter fullscreen mode Exit fullscreen mode

So long, and thanks for all the fish

I hope you enjoyed this post and that you will sleep even better in the future because you know, that your APIs are not only correctly implemented, but you also know that they are still up and running.

If you liked this post so much that you want to buy me a coffee, you can do so via buymeacoffee.com/blaimi

Top comments (1)

Collapse
 
blaimi profile image
Matthias Blümel

This should be a lot easier now since IntelliJ switched to GraalJS for interpreting the scripts here. Will see, what I can simplify here since the scripts code is IMHO very fragile.