The Open API specification is a widely adopted industry standard used to describe RESTful APIs. Originally referred to as the Swagger Framework, OpenAPI can be considered a RESTful API description language. It is used to provide a structured description of the API for humans as well as automated processing. Using the OpenAPI specification helps developers save time by automatic generation of documentation and validation of the endpoints. OpenAPI supports both JSON and XML.
How OpenAPI helped in our development workflow
Axlerant was entrusted with the task of developing a Drupal 8 based partial headless backend for a global NGO. The backend would be integrated with a React application, which would act as the Frontend of the system.
This meant that Axelerant and the Frontend developers had to come to a mutually acceptable format for the REST-based API endpoints in the backend. After careful consideration, the OpenAPI 3.0 specification was selected as the format for describing the APIs.
Using Open API helped the development in the following ways:
- It helped in designing the API by describing the endpoints and the valid responses.
- Specifications for our API could be hosted on the OpenAPI server.
- All stakeholders involved could see the API and accepted behavior.
- It automated the process of documentation of the API.
- The API specification can easily be versioned, so managing changes took less effort.
- It was a widely adopted standard, so some tools could be used to process the spec.
- And most importantly, we could use these tools to validate the endpoints against the spec using PHPUnit, leading to test automation and quicker deployments.
- This made the frontend and backend team truly decoupled, not having any dependencies on each other.
Validating REST API endpoints with OpenAPI and PHPUnit
OpenAPI specifications can be written in a swagger.yaml file with metadata about the spec, including the version and the formats used. Also, the specifications can be hosted on the open API hosting platform. This allowed us to fetch and download the latest specification and use commonly available validation libraries to validate the responses against each of our endpoints.
We had achieved this using the following steps:
- Installed PHPUnit and wrote unit test classes for each API endpoint.
- Fetched the latest version of the API spec swagger.yaml.
- We sent a test request to each of the endpoints and retrieved the responses.
- The validators available were used to test the responses against the spec to make the assertions.
The swagger file loader class
To fetch the latest API version from the Open API hosted site, we wrote a class that would always load the latest version from the API endpoint. This was implemented using Guzzle and would be used by the base class to load the validator see sample below.
The PHPUnit Base class
Since we needed to do a few setup operations for all the tests, we planned to write, and we had decided to write a base class extending the UnitTestCase class of Drupal. This would load the SwaggerFileLoader and also load the libraries.
The base class does the following:
- Calling the setup method required by the PHPUnit parent class.
- Instantiating the Guzzle HTTP client required for sending requests.
- Loading the Swagger file with the valid API specifications agreed by all stakeholders.
- And most importantly, it also loads the OpenAPI validator.
The OpenAPI validator package will validate the API endpoint responses against the same endpoint spec in swagger.yaml file. It is available by using the namespace League\OpenAPIValidation\PSR7\ValidatorBuilder and has to be installed as a separate composer package.
There are certain limitations of the OpenAPI ValidatorBuilder class; it only takes into account the field format and type but does not check the field name provided in the OpenAPI specification. This means validation will be passed even if the field name does not match with the specification, but format and type are correctly provided.
Sample PHPUnit test
Now, we combine everything with writing a unit test to test our sample endpoint and validate it against the swagger specification.
In the above sample, we can see that the Unit test extends the MyUnitTestBase. We use the Guzzle client to send a sample request to the example API endpoint. Once the received response is captured, we fetch the validator method defined in the parent class to validate the response.
To achieve that, we need to instantiate the OperationAddress class and pass the section in the swagger file with the endpoint & the method specification we want to test against. This helper class converts the input into a format that is readable by the validator class. The validator will then check if responses in the original endpoint and the spec match the one in the specification when called using PHPUnit.
And this is how we can use PHPUnit, OpenAPI, and swagger to build RESTful endpoints in Drupal 8. I hope this was helpful. Watch out this space for more such insights!