Validate Your PHP API Tests Against OpenAPI Definitions — A Laravel Example [2023 update]
OpenAPI definitions are great to generate documentations, but there is much more we can do with them

OpenAPI is a specification intended to describe RESTful APIs in JSON and YAML, with the aim of being understandable by humans and machines alike.
OpenAPI definitions are language-agnostic and can be used in a lot of different ways:
An OpenAPI definition can be used by documentation generation tools to display the API, code generation tools to generate servers and clients in various programming languages, testing tools, and many other use cases.
This article demonstrates how to write integration tests that compare API responses to OpenAPI 3+ definitions to validate that the former conform to the latter.
We will use the OpenAPI HttpFoundation Testing package in a fresh Laravel installation for which we’ll also generate a Swagger UI documentation using the L5 Swagger package.
The first part of the post will describe the issue and provide further context — if you’re just here for the code, you’re welcome to skip ahead and go to the Laravel example section straight away.
The issue
APIs are commonplace nowadays and the decent ones come with documentation describing the endpoints and how to use them. These documents come in various shapes and forms, but a fact they can’t escape is that they need to be updated every time the API changes.
To many developers, API documentation is an afterthought — it’s boring, tedious, and often unrewarding. Using annotations to keep the code and documentation in one place helps to some extent, but these are often painful to write and even the most willing developer is likely to introduce errors that won’t necessarily be caught by reviewers.
The result is documentation and API getting out of sync, leading to frustrated consumers.
Another goal of API maintenance is to ensure that existing endpoints keep functioning properly — regressions can and will appear over time, and may go unnoticed if there isn’t a proper testing strategy in place.
One approach is to write integration tests controlling the API’s behaviour and automatically detecting breaking changes as soon as they are introduced. While this is a good strategy, it isn’t foolproof — there’s no guarantee that the expectations set in the tests will always 100% match the documentation.
How can we make sure they remain in sync?
A solution
Let’s assume that we have an API documented with OpenAPI, some integration tests, and that we want to align the expectations of the latter with the operations described in the former.
OpenAPI comes with a growing number of tools built on top of it, pushing its utility far beyond the documenting aspect.
One tool destined for the PHP community and maintained by The PHP League is OpenAPI PSR-7 Message Validator, a package validating PSR-7 HTTP messages against OpenAPI definitions.
The idea is to compare HTTP requests and responses with OpenAPI definitions and return errors when they don’t match.
In other words, we can use this package to add an extra layer on top of our integration tests that will compare API requests and responses with the OpenAPI definitions describing our API and fail the test if they don’t match.
Here is a fancy diagram to illustrate the relationship between the API, the integration tests and the OpenAPI definition:

The definition describes the API, and the tests use the definition to make sure the API behaves the way the definition says it does.
All of a sudden, our OpenAPI definition becomes a reference for both our code and our tests — it acts as the API’s single source of truth.
PSR-7
One caveat of the OpenAPI PSR-7 Message Validator package is that, as its name indicates, it only works with PSR-7 messages.
The issue is that not all frameworks support this standard by default — in fact, a lot of them use Symfony’s HttpFoundation component under the hood, whose requests and responses do not implement that standard out of the box.
The Symfony folks thought of this, however, and provided a bridge that converts HttpFoundation objects to PSR-7 ones. The bridge simply needs a PSR-7 and PSR-17 factory, for which they suggest using Tobias Nyholm’s PSR-7 implementation.
All these pieces are brought together by OpenAPI HttpFoundation Testing, a package allowing developers to back their integration tests with OpenAPI definitions in applications relying on the HttpFoundation component.
Let’s see how to use it in a Laravel project, which falls into this category.
A Laravel example
The code featured in this section is also available as a GitHub repository for reference.
First, let’s create a new Laravel 10 project, using Composer:
$ composer create-project --prefer-dist laravel/laravel openapi-example "10.*"
Enter the project’s root folder and instal a couple of dependencies:
$ cd openapi-example
$ composer require --dev osteel/openapi-httpfoundation-testing
$ composer require darkaonline/l5-swagger
The first one is the OpenAPI HttpFoundation Testing package mentioned earlier, which we instal as a development dependency as it’s intended to be used as part of our test suite.
The second one is L5 Swagger, a popular package bringing Swagger PHP and Swagger UI to Laravel. We actually don’t need Swagger PHP here, as it uses Doctrine annotations to generate OpenAPI definitions and we’re going to manually write our own instead. We do need Swagger UI, however, and L5 Swagger conveniently adapts it to work with Laravel.
If you’re wondering, the -W
option is simply here to also update related dependencies and thus avoid conflicts.
To make sure Swagger PHP doesn’t overwrite the OpenAPI definition, let’s set the following environment variable in the .env
file, at the root of the project:
L5_SWAGGER_GENERATE_ALWAYS=false
Let’s also make YAML the default format:
L5_FORMAT_TO_USE_FOR_DOCS=yaml
Create a file named api-docs.yaml
in the storage/api-docs
folder (which you need to create), and add the following content to it: