PHPackages                             helios-ag/openapi-psr7-validator - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. helios-ag/openapi-psr7-validator

ActiveLibrary[HTTP &amp; Networking](/categories/http)

helios-ag/openapi-psr7-validator
================================

Validate PSR-7 messages against OpenAPI (3.0.2) specifications expressed in YAML or JSON

0.23(2d ago)01↓100%MITPHPPHP &gt;=7.2

Since Apr 6Pushed 2d agoCompare

[ Source](https://github.com/helios-ag/openapi-psr7-validator)[ Packagist](https://packagist.org/packages/helios-ag/openapi-psr7-validator)[ Docs](https://github.com/thephpleague/openapi-psr7-validator)[ RSS](/packages/helios-ag-openapi-psr7-validator/feed)WikiDiscussions master Synced today

READMEChangelog (1)Dependencies (18)Versions (3)Used By (0)

[![Latest Stable Version](https://camo.githubusercontent.com/2c9cec0fd88417c0f7aa7609e55bd2ca307fcf2ee96250e3cf092453e7d3e3a2/68747470733a2f2f706f7365722e707567782e6f72672f6c65616775652f6f70656e6170692d707372372d76616c696461746f722f762f737461626c65)](https://packagist.org/packages/league/openapi-psr7-validator)[![Build Status](https://camo.githubusercontent.com/4f4bdd3e60c8901e09613c9132e8534660236bd0167d11bd308044e4463df2d8/68747470733a2f2f7472617669732d63692e6f72672f7468657068706c65616775652f6f70656e6170692d707372372d76616c696461746f722e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/thephpleague/openapi-psr7-validator)[![License](https://camo.githubusercontent.com/745ec7052995bd4557f8355d3e9bb2908f44987db1fe5ecaa494a259447fc8bf/68747470733a2f2f706f7365722e707567782e6f72672f6c65616775652f6f70656e6170692d707372372d76616c696461746f722f6c6963656e7365)](https://packagist.org/packages/lezhnev74/openapi-psr7-validator)[![contributions welcome](https://camo.githubusercontent.com/382079383bf5ec051cfa878df7b3d9a70a5f5052e573c67033d4d3f7e376a6d4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f6e747269627574696f6e732d77656c636f6d652d627269676874677265656e2e737667)](https://camo.githubusercontent.com/382079383bf5ec051cfa878df7b3d9a70a5f5052e573c67033d4d3f7e376a6d4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f6e747269627574696f6e732d77656c636f6d652d627269676874677265656e2e737667)

OpenAPI PSR-7 Message (HTTP Request/Response) Validator
=======================================================

[](#openapi-psr-7-message-http-requestresponse-validator)

This package can validate PSR-7 messages against OpenAPI (3.0.x) specifications expressed in YAML or JSON.

[![](image.jpg)](image.jpg)

Installation
------------

[](#installation)

```
composer require league/openapi-psr7-validator

```

OpenAPI (OAS) Terms
-------------------

[](#openapi-oas-terms)

There are some specific terms that are used in the package. These terms come from OpenAPI:

- `specification` - an OpenAPI document describing an API, expressed in JSON or YAML file
- `data` - actual thing that we validate against a specification, including body and metadata
- `schema` - the part of the specification that describes the body of the request / response
- `keyword` - properties that are used to describe the instance are called key words, or schema keywords
- `path` - a relative path to an individual endpoint
- `operation` - a method that we apply on the path (like `get /password`)
- `response` - described response (includes status code, content types etc)

How To Validate
---------------

[](#how-to-validate)

### ServerRequest Message

[](#serverrequest-message)

You can validate `\Psr\Http\Message\ServerRequestInterface` instance like this:

```
$yamlFile = "api.yaml";
$jsonFile = "api.json";

$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromYamlFile($yamlFile)->getServerRequestValidator();
#or
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromYaml(file_get_contents($yamlFile))->getServerRequestValidator();
#or
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromJson(file_get_contents($jsonFile))->getServerRequestValidator();
#or
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromJsonFile($jsonFile)->getServerRequestValidator();
#or
$schema = new \cebe\openapi\spec\OpenApi(); // generate schema object by hand
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromSchema($schema)->getServerRequestValidator();

$match = $validator->validate($request);
```

As a result you would get and `OperationAddress $match` which has matched the given request. If you already know the operation which should match your request (i.e you have routing in your project), you can use `RouterRequestValidator`

```
$address = new \League\OpenAPIValidation\PSR7\OperationAddress('/some/operation', 'post');

$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromSchema($schema)->getRoutedRequestValidator();

$validator->validate($address, $request);
```

This would simplify validation a lot and give you more performance.

### Request Message

[](#request-message)

You can validate `\Psr\Http\Message\RequestInterface` instance like this:

```
$yamlFile = "api.yaml";
$jsonFile = "api.json";

$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromYamlFile($yamlFile)->getRequestValidator();
#or
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromYaml(file_get_contents($yamlFile))->getRequestValidator();
#or
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromJson(file_get_contents($jsonFile))->getRequestValidator();
#or
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromJsonFile($jsonFile)->getRequestValidator();
#or
$schema = new \cebe\openapi\spec\OpenApi(); // generate schema object by hand
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromSchema($schema)->getRequestValidator();

$match = $validator->validate($request);
```

### Response Message

[](#response-message)

Validation of `\Psr\Http\Message\ResponseInterface` is a bit more complicated . Because you need not only YAML file and Response itself, but also you need to know which operation this response belongs to (in terms of OpenAPI).

Example:

```
$yamlFile = "api.yaml";
$jsonFile = "api.json";

$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromYamlFile($yamlFile)->getResponseValidator();
#or
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromYaml(file_get_contents($yamlFile))->getResponseValidator();
#or
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromJson(file_get_contents($jsonFile))->getResponseValidator();
#or
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromJsonFile($jsonFile)->getResponseValidator();
#or
$schema = new \cebe\openapi\spec\OpenApi(); // generate schema object by hand
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromSchema($schema)->getResponseValidator();

$operation = new \League\OpenAPIValidation\PSR7\OperationAddress('/password/gen', 'get') ;

$validator->validate($operation, $response);
```

### Reuse Schema After Validation

[](#reuse-schema-after-validation)

`\League\OpenAPIValidation\PSR7\ValidatorBuilder` reads and compiles schema in memory as instance of `\cebe\openapi\spec\OpenApi`. Validators use this instance to perform validation logic. You can reuse this instance after the validation like this:

```
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromYamlFile($yamlFile)->getServerRequestValidator();
# or
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromYamlFile($yamlFile)->getResponseValidator();

/** @var \cebe\openapi\spec\OpenApi */
$openApi = $validator->getSchema();
```

### PSR-15 Middleware

[](#psr-15-middleware)

PSR-15 middleware can be used like this:

```
$yamlFile = 'api.yaml';
$jsonFile = 'api.json';

$psr15Middleware = (new \League\OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromYamlFile($yamlFile)->getValidationMiddleware();
#or
$psr15Middleware = (new \League\OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromYaml(file_get_contents($yamlFile))->getValidationMiddleware();
#or
$psr15Middleware = (new \League\OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromJsonFile($jsonFile)->getValidationMiddleware();
#or
$psr15Middleware = (new \League\OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromJson(file_get_contents($jsonFile))->getValidationMiddleware();
#or
$schema = new \cebe\openapi\spec\OpenApi(); // generate schema object by hand
$validator = (new \League\OpenAPIValidation\PSR7\ValidationMiddlewareBuilder)->fromSchema($schema)->getValidationMiddleware();
```

### SlimFramework Middleware

[](#slimframework-middleware)

Slim framework uses slightly different middleware interface, so here is an adapter which you can use like this:

```
$yamlFile = 'api.yaml';
$jsonFile = 'api.json';

$psr15Middleware = (new \League\OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromYamlFile($yamlFile)->getValidationMiddleware();
#or
$psr15Middleware = (new \League\OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromYaml(file_get_contents($yamlFile))->getValidationMiddleware();
#or
$psr15Middleware = (new \League\OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromJsonFile($jsonFile)->getValidationMiddleware();
#or
$psr15Middleware = (new \League\OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromJson(file_get_contents($jsonFile))->getValidationMiddleware();
#or
$schema = new \cebe\openapi\spec\OpenApi(); // generate schema object by hand
$validator = (new \League\OpenAPIValidation\PSR7\ValidationMiddlewareBuilder)->fromSchema($schema)->getValidationMiddleware();

$slimMiddleware = new \League\OpenAPIValidation\PSR15\SlimAdapter($psr15Middleware);

/** @var \Slim\App $app */
$app->add($slimMiddleware);
```

### Caching Layer / PSR-6 Support

[](#caching-layer--psr-6-support)

PSR-7 Validator has a built-in caching layer (based on [PSR-6](https://www.php-fig.org/psr/psr-6/) interfaces) which saves time on parsing OpenAPI specs. It is optional. You enable caching if you pass a configured Cache Pool Object to the static constructor like this:

```
// Configure a PSR-6 Cache Pool
$cachePool = new ArrayCachePool();

// Pass it as a 2nd argument
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)
    ->fromYamlFile($yamlFile)
    ->setCache($cachePool)
    ->getResponseValidator();
# or
$psr15Middleware = (new \OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)
    ->fromYamlFile($yamlFile)
    ->setCache($cachePool)
    ->getValidationMiddleware();
```

You can use `->setCache($pool, $ttl)` call for both PSR-7 and PSR-15 builder in order to set [proper expiration ttl in seconds (or explicit `null`)](https://www.php-fig.org/psr/psr-6/#definitions)

If you want take control over the cache key for schema item, or your cache does not support cache key generation by itself you can `->overrideCacheKey('my_custom_key')` to ensure cache uses key you want.

### Standalone OpenAPI Validator

[](#standalone-openapi-validator)

The package contains a standalone validator which can validate any data against an OpenAPI schema like this:

```
$spec = resolveReferences(new ReferenceContext($spec, "/"));
$schema = new cebe\openapi\spec\Schema($spec->schema);

try {
    (new \League\OpenAPIValidation\Schema\SchemaValidator())->validate($data, $schema);
} catch(\League\OpenAPIValidation\Schema\Exception\KeywordMismatch $e) {
    // you can evaluate failure details
    // $e->keyword() == "enum"
    // $e->data() == "c"
    // $e->dataBreadCrumb()->buildChain() -- only for nested data
}
```

Custom Type Formats
-------------------

[](#custom-type-formats)

As you know, OpenAPI allows you to add formats to types:

```
schema:
  type: string
  format: binary
```

This package contains a bunch of built-in format validators:

- `string` type:
    - `byte`
    - `date`
    - `date-time`
    - `email`
    - `hostname`
    - `ipv4`
    - `ipv6`
    - `uri`
    - `uuid` (uuid4)
- `number` type
    - `float`
    - `double`

You can also add your own formats. Like this:

```
# A format validator must be a callable
# It must return bool value (true if format matched the data, false otherwise)

# A callable class:
$customFormat = new class()
{
    function __invoke($value): bool
    {
        return $value === "good value";
    }
};

# Or just a closure:
$customFormat = function ($value): bool {
    return $value === "good value";
};

# Register your callable like this before validating your data
\League\OpenAPIValidation\Schema\TypeFormats\FormatsContainer::registerFormat('string', 'custom', $customFormat);
```

Exceptions
----------

[](#exceptions)

The package throws a list of various exceptions which you can catch and handle. There are some of them:

- Schema related:
    - `\League\OpenAPIValidation\Schema\Exception\KeywordMismatch` - Indicates that data was not matched against a schema's keyword
        - `\League\OpenAPIValidation\Schema\Exception\TypeMismatch` - Validation for `type` keyword failed against a given data. For example `type:string` and value is `12`
        - `\League\OpenAPIValidation\Schema\Exception\FormatMismatch` - data mismatched a given type format. For example `type: string, format: email` won't match `not-email`.
- PSR7 Messages related:
    - `\League\OpenAPIValidation\PSR7\Exception\NoContentType` - HTTP message(request/response) contains no Content-Type header. General HTTP errors.
    - `\League\OpenAPIValidation\PSR7\Exception\NoPath` - path is not found in the spec
    - `\League\OpenAPIValidation\PSR7\Exception\NoOperation` - operation os not found in the path
    - `\League\OpenAPIValidation\PSR7\Exception\NoResponseCode` - response code not found under the operation in the spec
    - Validation exceptions (check parent exception for possible root causes):
        - `\League\OpenAPIValidation\PSR7\Exception\ValidationFailed` - generic exception for failed PSR-7 message
        - `\League\OpenAPIValidation\PSR7\Exception\Validation\InvalidBody` - body does not match schema
        - `\League\OpenAPIValidation\PSR7\Exception\Validation\InvalidCookies` - cookies does not match schema or missing required cookie
        - `\League\OpenAPIValidation\PSR7\Exception\Validation\InvalidHeaders` - header does not match schema or missing required header
        - `\League\OpenAPIValidation\PSR7\Exception\Validation\InvalidPath` - path does not match pattern or pattern values does not match schema
        - `\League\OpenAPIValidation\PSR7\Exception\Validation\InvalidQueryArgs` - query args does not match schema or missing required argument
        - `\League\OpenAPIValidation\PSR7\Exception\Validation\InvalidSecurity` - request does not match security schema or invalid security headers
    - Request related:
        - `\League\OpenAPIValidation\PSR7\Exception\MultipleOperationsMismatchForRequest` - request matched multiple operations in the spec, but validation failed for all of them.

Testing
-------

[](#testing)

You can run the tests with:

```
vendor/bin/phpunit

```

Contribution Guide
------------------

[](#contribution-guide)

Feel free to open an Issue or add a Pull request. There is a certain code style that this package follows: [doctrine/coding-standard](https://www.doctrine-project.org/projects/doctrine-coding-standard/en/latest/reference/index.html#introduction).

To conform to this style please use a git hook, shipped with this package at `.githooks/pre-commit`.

How to use it:

1. Clone the package locally and navigate to the folder
2. Create a symlink to the hook like this: `ln -s -f ../../.githooks/pre-commit .git/hooks/pre-commit`
3. Add execution rights: `chmod +x .git/hooks/pre-commit`
4. Now commit any new changes and the code will be checked and formatted accordingly.
5. If there are any issues with your code, check the log here: `.phpcs-report.txt`

Credits
-------

[](#credits)

People:

- [Dmitry Lezhnev](https://github.com/lezhnev74)
- [Carsten Brandt](https://github.com/cebe)
- [Samuel Nela](https://github.com/samnela)
- [Pavel Batanov](https://github.com/scaytrase)
- [Christopher L Bray](https://github.com/brayniverse)
- [David Pauli](https://github.com/dpauli)
- [Jason Judge](https://github.com/judgej)
- [Yannick Chenot](https://github.com/osteel)
- [TarasBK](https://github.com/TarasBK)
- [Jason B. Standing](https://github.com/jasonbstanding)
- [Dmytro Demchyna](https://github.com/dmytro-demchyna)
- [Will Chambers](https://github.com/willchambers99)
- [Ignacio](https://github.com/imefisto)
- A big thank you to [Henrik Karlström](https://github.com/hkarlstrom) who kind of inspired me to work on this package.

Resources:

- Icons made by Freepik, licensed by CC 3.0 BY
- [cebe/php-openapi](https://github.com/cebe/php-openapi) package for Reading OpenAPI files
- [slim3-psr15](https://github.com/bnf/slim3-psr15) package for Slim middleware adapter

License
-------

[](#license)

The MIT License (MIT). Please see `License.md` file for more information.

TODO
----

[](#todo)

- Support Discriminator Object (note: apparently, this is not so straightforward, as discriminator can point to any external scheme)

###  Health Score

34

—

LowBetter than 77% of packages

Maintenance99

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community19

Small or concentrated contributor base

Maturity19

Early-stage or recently created project

 Bus Factor1

Top contributor holds 55.9% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

2d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/fdaf9345391fb6aac209cff89d61dcb949999d4a6867212b30577831eb5bc8d8?d=identicon)[helios](/maintainers/helios)

---

Top Contributors

[![lezhnev74](https://avatars.githubusercontent.com/u/10206110?v=4)](https://github.com/lezhnev74 "lezhnev74 (223 commits)")[![scaytrase](https://avatars.githubusercontent.com/u/6578413?v=4)](https://github.com/scaytrase "scaytrase (73 commits)")[![rogervila](https://avatars.githubusercontent.com/u/6053012?v=4)](https://github.com/rogervila "rogervila (23 commits)")[![sunspikes](https://avatars.githubusercontent.com/u/75611?v=4)](https://github.com/sunspikes "sunspikes (16 commits)")[![canvural](https://avatars.githubusercontent.com/u/1574232?v=4)](https://github.com/canvural "canvural (10 commits)")[![m0003r](https://avatars.githubusercontent.com/u/692310?v=4)](https://github.com/m0003r "m0003r (7 commits)")[![KentarouTakeda](https://avatars.githubusercontent.com/u/4785040?v=4)](https://github.com/KentarouTakeda "KentarouTakeda (7 commits)")[![digilist](https://avatars.githubusercontent.com/u/833667?v=4)](https://github.com/digilist "digilist (4 commits)")[![nektru](https://avatars.githubusercontent.com/u/9137294?v=4)](https://github.com/nektru "nektru (4 commits)")[![ckilb](https://avatars.githubusercontent.com/u/7283097?v=4)](https://github.com/ckilb "ckilb (3 commits)")[![imefisto](https://avatars.githubusercontent.com/u/3299088?v=4)](https://github.com/imefisto "imefisto (3 commits)")[![bizurkur](https://avatars.githubusercontent.com/u/16649887?v=4)](https://github.com/bizurkur "bizurkur (3 commits)")[![Yarre](https://avatars.githubusercontent.com/u/2134158?v=4)](https://github.com/Yarre "Yarre (2 commits)")[![brayniverse](https://avatars.githubusercontent.com/u/945367?v=4)](https://github.com/brayniverse "brayniverse (2 commits)")[![camilledejoye](https://avatars.githubusercontent.com/u/11501572?v=4)](https://github.com/camilledejoye "camilledejoye (2 commits)")[![ctipggroup](https://avatars.githubusercontent.com/u/30641668?v=4)](https://github.com/ctipggroup "ctipggroup (2 commits)")[![frankdejonge](https://avatars.githubusercontent.com/u/534693?v=4)](https://github.com/frankdejonge "frankdejonge (2 commits)")[![Identity-labs](https://avatars.githubusercontent.com/u/600296?v=4)](https://github.com/Identity-labs "Identity-labs (1 commits)")[![helios-ag](https://avatars.githubusercontent.com/u/334907?v=4)](https://github.com/helios-ag "helios-ag (1 commits)")[![hansott](https://avatars.githubusercontent.com/u/3886384?v=4)](https://github.com/hansott "hansott (1 commits)")

---

Tags

httpvalidationopenapipsr7

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/helios-ag-openapi-psr7-validator/health.svg)

```
[![Health](https://phpackages.com/badges/helios-ag-openapi-psr7-validator/health.svg)](https://phpackages.com/packages/helios-ag-openapi-psr7-validator)
```

###  Alternatives

[league/openapi-psr7-validator

Validate PSR-7 messages against OpenAPI (3.0.2) specifications expressed in YAML or JSON

55615.9M69](/packages/league-openapi-psr7-validator)[kevinrob/guzzle-cache-middleware

A HTTP/1.1 Cache for Guzzle 6. It's a simple Middleware to be added in the HandlerStack. (RFC 7234)

43117.4M104](/packages/kevinrob-guzzle-cache-middleware)[phpro/http-tools

HTTP tools for developing more consistent HTTP implementations.

28137.8k](/packages/phpro-http-tools)[mezzio/mezzio-authentication-oauth2

OAuth2 (server) authentication middleware for Mezzio and PSR-7 applications.

28483.0k2](/packages/mezzio-mezzio-authentication-oauth2)[laudis/neo4j-php-client

Neo4j-PHP-Client is the most advanced PHP Client for Neo4j

184616.9k31](/packages/laudis-neo4j-php-client)[mezzio/mezzio-authentication

Authentication middleware for Mezzio and PSR-7 applications

121.6M25](/packages/mezzio-mezzio-authentication)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
