{"id":13704199,"url":"https://github.com/lezhnev74/openapi-psr7-validator","last_synced_at":"2025-04-05T07:07:14.937Z","repository":{"id":62516957,"uuid":"184420719","full_name":"lezhnev74/openapi-psr7-validator","owner":"lezhnev74","description":"It validates PSR-7 messages (HTTP request/response) against OpenAPI specifications","archived":false,"fork":false,"pushed_at":"2021-10-06T10:50:42.000Z","size":471,"stargazers_count":169,"open_issues_count":8,"forks_count":10,"subscribers_count":13,"default_branch":"master","last_synced_at":"2024-10-13T12:29:30.798Z","etag":null,"topics":["openapi","openapi3","php","psr-7","validation"],"latest_commit_sha":null,"homepage":"https://lessthan12ms.com/openapi-with-php-documenting-and-testing-api-automatically/","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lezhnev74.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-01T13:32:30.000Z","updated_at":"2023-12-29T14:12:28.000Z","dependencies_parsed_at":"2022-11-02T13:45:37.726Z","dependency_job_id":null,"html_url":"https://github.com/lezhnev74/openapi-psr7-validator","commit_stats":null,"previous_names":[],"tags_count":38,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lezhnev74%2Fopenapi-psr7-validator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lezhnev74%2Fopenapi-psr7-validator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lezhnev74%2Fopenapi-psr7-validator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lezhnev74%2Fopenapi-psr7-validator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lezhnev74","download_url":"https://codeload.github.com/lezhnev74/openapi-psr7-validator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247299832,"owners_count":20916190,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["openapi","openapi3","php","psr-7","validation"],"created_at":"2024-08-02T21:01:05.511Z","updated_at":"2025-04-05T07:07:14.918Z","avatar_url":"https://github.com/lezhnev74.png","language":"PHP","funding_links":[],"categories":["目录","HTTP"],"sub_categories":["HTTP客户端 HTTP Client"],"readme":"[![Latest Stable Version](https://poser.pugx.org/lezhnev74/openapi-psr7-validator/v/stable)](https://packagist.org/packages/lezhnev74/openapi-psr7-validator)\n[![Build Status](https://travis-ci.org/lezhnev74/openapi-psr7-validator.svg?branch=master)](https://travis-ci.org/lezhnev74/openapi-psr7-validator)\n[![License](https://poser.pugx.org/lezhnev74/openapi-psr7-validator/license)](https://packagist.org/packages/lezhnev74/openapi-psr7-validator)\n![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg)\n\n# NOTICE - THE PACKAGE HAS BEEN CONTRIBUTED TO THE PHP LEAGUE\n\nGo to https://github.com/thephpleague/openapi-psr7-validator\n\nThis package is here for existing users only.\n\n# OpenAPI PSR-7 Message (HTTP Request/Response) Validator\nThis package can validate PSR-7 messages against OpenAPI (3.0.x) specifications \nexpressed in YAML or JSON. \n\n![](image.jpg)\n\n## Installation\n```\ncomposer require lezhnev74/openapi-psr7-validator\n```\n\n## OpenAPI (OAS) Terms\nThere are some specific terms that are used in the package. These terms come \nfrom OpenAPI:\n- `specification` - an OpenAPI document describing an API, expressed in JSON or YAML file\n- `data` - actual thing that we validate against a specification, including body and metadata\n- `schema` - the part of the specification that describes the body of the request / response\n- `keyword` - properties that are used to describe the instance are called key\nwords, or schema keywords\n- `path` - a relative path to an individual endpoint\n- `operation` - a method that we apply on the path (like `get /password`)\n- `response` - described response (includes status code, content types etc)\n\n\n## How To Validate\n\n### ServerRequest Message\nYou can validate `\\Psr\\Http\\Message\\ServerRequestInterface` instance like this:\n\n```php\n$yamlFile = \"api.yaml\";\n$jsonFile = \"api.json\";\n\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromYamlFile($yamlFile)-\u003egetServerRequestValidator();\n#or\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromYaml(file_get_contents($yamlFile))-\u003egetServerRequestValidator();\n#or\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromJson(file_get_contents($jsonFile))-\u003egetServerRequestValidator();\n#or\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromJsonFile($jsonFile)-\u003egetServerRequestValidator();\n#or\n$schema = new \\cebe\\openapi\\spec\\OpenApi(); // generate schema object by hand\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromSchema($schema)-\u003egetServerRequestValidator();\n\n$match = $validator-\u003evalidate($request);\n```\n\nAs a result you would get and `OperationAddress $match` which has matched the given request. If you already know\nthe operation which should match your request (i.e you have routing in your project), you can use \n`RouterRequestValidator`\n\n```php\n$address = new \\OpenAPIValidation\\PSR7\\OperationAddress('/some/operation', 'post');\n\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromSchema($schema)-\u003egetRoutedRequestValidator();\n\n$validator-\u003evalidate($address, $request);\n```\n\nThis would simplify validation a lot and give you more performance.\n\n### Request Message\nYou can validate `\\Psr\\Http\\Message\\RequestInterface` instance like this:\n\n```php\n$yamlFile = \"api.yaml\";\n$jsonFile = \"api.json\";\n\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromYamlFile($yamlFile)-\u003egetRequestValidator();\n#or\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromYaml(file_get_contents($yamlFile))-\u003egetRequestValidator();\n#or\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromJson(file_get_contents($jsonFile))-\u003egetRequestValidator();\n#or\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromJsonFile($jsonFile)-\u003egetRequestValidator();\n#or\n$schema = new \\cebe\\openapi\\spec\\OpenApi(); // generate schema object by hand\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromSchema($schema)-\u003egetRequestValidator();\n\n$match = $validator-\u003evalidate($request);\n```\n\n### Response Message\nValidation of `\\Psr\\Http\\Message\\ResponseInterface` is a bit more complicated\n. Because you need not only YAML file and Response itself, but also you need \nto know which operation this response belongs to (in terms of OpenAPI).\n\nExample:\n\n```php\n$yamlFile = \"api.yaml\";\n$jsonFile = \"api.json\";\n\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromYamlFile($yamlFile)-\u003egetResponseValidator();\n#or\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromYaml(file_get_contents($yamlFile))-\u003egetResponseValidator();\n#or\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromJson(file_get_contents($jsonFile))-\u003egetResponseValidator();\n#or\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromJsonFile($jsonFile)-\u003egetResponseValidator();\n#or\n$schema = new \\cebe\\openapi\\spec\\OpenApi(); // generate schema object by hand\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromSchema($schema)-\u003egetResponseValidator();\n\n$operation = new \\OpenAPIValidation\\PSR7\\OperationAddress('/password/gen', 'get') ;\n\n$validator-\u003evalidate($operation, $request);\n```\n\n### Reuse Schema After Validation\n\n`\\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:\n\n```php\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromYamlFile($yamlFile)-\u003egetServerRequestValidator();\n# or\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)-\u003efromYamlFile($yamlFile)-\u003egetResponseValidator();\n\n/** @var \\cebe\\openapi\\spec\\OpenApi */\n$openApi = $validator-\u003egetSchema();\n```\n\n### Request Message\n`\\Psr\\Http\\Message\\RequestInterface` validation is not implemented. \n\n### PSR-15 Middleware\nPSR-15 middleware can be used like this:\n\n```php\n$yamlFile = 'api.yaml';\n$jsonFile = 'api.json';\n\n$psr15Middleware = (new \\OpenAPIValidation\\PSR15\\ValidationMiddlewareBuilder)-\u003efromYamlFile($yamlFile)-\u003egetValidationMiddleware();\n#or\n$psr15Middleware = (new \\OpenAPIValidation\\PSR15\\ValidationMiddlewareBuilder)-\u003efromYaml(file_get_contents($yamlFile))-\u003egetValidationMiddleware();\n#or\n$psr15Middleware = (new \\OpenAPIValidation\\PSR15\\ValidationMiddlewareBuilder)-\u003efromJsonFile($jsonFile)-\u003egetValidationMiddleware();\n#or\n$psr15Middleware = (new \\OpenAPIValidation\\PSR15\\ValidationMiddlewareBuilder)-\u003efromJson(file_get_contents($jsonFile))-\u003egetValidationMiddleware();\n#or\n$schema = new \\cebe\\openapi\\spec\\OpenApi(); // generate schema object by hand\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidationMiddlewareBuilder)-\u003efromSchema($schema)-\u003egetValidationMiddleware();\n```\n\n### SlimFramework Middleware\nSlim framework uses slightly different middleware interface, so here is an \nadapter which you can use like this:\n\n```php\n$yamlFile = 'api.yaml';\n$jsonFile = 'api.json';\n\n$psr15Middleware = (new \\OpenAPIValidation\\PSR15\\ValidationMiddlewareBuilder)-\u003efromYamlFile($yamlFile)-\u003egetValidationMiddleware();\n#or\n$psr15Middleware = (new \\OpenAPIValidation\\PSR15\\ValidationMiddlewareBuilder)-\u003efromYaml(file_get_contents($yamlFile))-\u003egetValidationMiddleware();\n#or\n$psr15Middleware = (new \\OpenAPIValidation\\PSR15\\ValidationMiddlewareBuilder)-\u003efromJsonFile($jsonFile)-\u003egetValidationMiddleware();\n#or\n$psr15Middleware = (new \\OpenAPIValidation\\PSR15\\ValidationMiddlewareBuilder)-\u003efromJson(file_get_contents($jsonFile))-\u003egetValidationMiddleware();\n#or\n$schema = new \\cebe\\openapi\\spec\\OpenApi(); // generate schema object by hand\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidationMiddlewareBuilder)-\u003efromSchema($schema)-\u003egetValidationMiddleware();\n\n$slimMiddleware = new \\OpenAPIValidation\\PSR15\\SlimAdapter($psr15Middleware);\n\n/** @var \\Slim\\App $app */\n$app-\u003eadd($slimMiddleware);\n```\n\n### Caching Layer / PSR-6 Support\nPSR-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.\nYou enable caching if you pass a configured Cache Pool Object to the static constructor like this:\n```php\n// Configure a PSR-6 Cache Pool\n$cachePool = new ArrayCachePool();\n\n// Pass it as a 2nd argument\n$validator = (new \\OpenAPIValidation\\PSR7\\ValidatorBuilder)\n    -\u003efromYamlFile($yamlFile)\n    -\u003esetCache($cachePool)\n    -\u003egetResponseValidator();\n# or\n\\OpenAPIValidation\\PSR15\\ValidationMiddleware::fromYamlFile($yamlFile, $cachePool);\n```\n\nYou can use `-\u003esetCache($pool, $ttl)` call for both PSR-7 and PSR-15 builder in order to set \n[proper expiration ttl in seconds (or explicit `null`)](https://www.php-fig.org/psr/psr-6/#definitions)\n\nIf you want take control over the cache key for schema item, or your cache does not support cache key generation by itself\nyou can `-\u003eoverrideCacheKey('my_custom_key')` to ensure cache uses key you want.\n\n### Standalone OpenAPI Validator\nThe package contains a standalone validator which can validate any data \nagainst an OpenAPI schema like this:\n\n```php\n$spec = \u003c\u003c\u003cSPEC\nschema:\n  type: string\n  enum:\n  - a\n  - b\nSPEC;\n$data = \"c\";\n\n$spec   = cebe\\openapi\\Reader::readFromYaml($spec);\n# (optional) reference resolving\n$spec-\u003eresolveReferences(new ReferenceContext($spec, \"/\"));\n$schema = new cebe\\openapi\\spec\\Schema($spec-\u003eschema);\n\ntry {\n    (new \\OpenAPIValidation\\Schema\\SchemaValidator())-\u003evalidate($data, $schema);\n} catch(\\OpenAPIValidation\\Schema\\Exception\\KeywordMismatch $e) {\n    // you can evaluate failure details\n    // $e-\u003ekeyword() == \"enum\"\n    // $e-\u003edata() == \"c\"\n    // $e-\u003edataBreadCrumb()-\u003ebuildChain() -- only for nested data\n}\n```\n\n## Custom Type Formats\nAs you know, OpenAPI allows you to add formats to types:\n\n```yaml\nschema:\n  type: string\n  format: binary\n```\n\nThis package contains a bunch of built-in format validators:\n- `string` type:\n    - `byte`\n    - `date`\n    - `date-time`\n    - `email`\n    - `hostname`\n    - `ipv4`\n    - `ipv6`\n    - `uri`\n    - `uuid` (uuid4)\n- `number` type\n    - `float`\n    - `double`\n\nYou can also add your own formats. Like this:\n```php\n# A format validator must be a callable\n# It must return bool value (true if format matched the data, false otherwise)\n\n# A callable class:\n$customFormat = new class()\n{\n    function __invoke($value): bool\n    {\n        return $value === \"good value\";\n    }\n};\n\n# Or just a closure:\n$customFormat = function ($value): bool {\n    return $value === \"good value\";\n};\n\n# Register your callable like this before validating your data\n\\OpenAPIValidation\\Schema\\TypeFormats\\FormatsContainer::registerFormat('string', 'custom', $customFormat);\n```\n\n## Exceptions\nThe package throws a list of various exceptions which you can catch and handle. There are some of them:\n- Schema related:\n    - `\\OpenAPIValidation\\Schema\\Exception\\KeywordMismatch` - Indicates that data was not matched against a schema's keyword\n        - `\\OpenAPIValidation\\Schema\\Exception\\TypeMismatch` - Validation for `type` keyword failed against a given data. For example `type:string` and value is `12`\n        - `\\OpenAPIValidation\\Schema\\Exception\\FormatMismatch` - data mismatched a given type format. For example `type: string, format: email` won't match `not-email`.\n- PSR7 Messages related:\n    - `\\OpenAPIValidation\\PSR7\\Exception\\NoContentType` - HTTP message(request/response) contains no Content-Type header. General HTTP errors.\n    - `\\OpenAPIValidation\\PSR7\\Exception\\NoPath` - path is not found in the spec\n    - `\\OpenAPIValidation\\PSR7\\Exception\\NoOperation` - operation os not found in the path\n    - `\\OpenAPIValidation\\PSR7\\Exception\\NoResponseCode` - response code not found under the operation in the spec\n    - Validation exceptions (check parent exception for possible root causes):\n        - `\\OpenAPIValidation\\PSR7\\Exception\\ValidationFailed` - generic exception for failed PSR-7 message\n        - `\\OpenAPIValidation\\PSR7\\Exception\\Validation\\InvalidBody` - body does not match schema\n        - `\\OpenAPIValidation\\PSR7\\Exception\\Validation\\InvalidCookies` - cookies does not match schema or missing required cookie\n        - `\\OpenAPIValidation\\PSR7\\Exception\\Validation\\InvalidHeaders` - header does not match schema or missing required header\n        - `\\OpenAPIValidation\\PSR7\\Exception\\Validation\\InvalidPath` - path does not match pattern or pattern values does not match schema\n        - `\\OpenAPIValidation\\PSR7\\Exception\\Validation\\InvalidQueryArgs` - query args does not match schema or missing required argument\n        - `\\OpenAPIValidation\\PSR7\\Exception\\Validation\\InvalidSecurity` - request does not match security schema or invalid security headers\n    - Request related:\n        - `\\OpenAPIValidation\\PSR7\\Exception\\MultipleOperationsMismatchForRequest` - request matched multiple operations in the spec, \n        but validation failed for all of them.\n\n## Testing\nYou can run the tests with:\n\n```\nvendor/bin/phpunit\n```\n\n## Contribution Guide\nFeel free to open an Issue or add a Pull request. \nThere 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).\n\nTo conform to this style please use a git hook, shipped with this package at `.githooks/pre-commit`.\n\nHow to use it:\n1. Clone the package locally and navigate to the folder\n2. Create a symlink to the hook like this: `ln -s -f ../../.githooks/pre-commit .git/hooks/pre-commit`\n3. Add execution rights: `chmod +x .git/hooks/pre-commit`\n4. Now commit any new changes and the code will be checked and formatted accordingly.\n5. If there are any issues with your code, check the log here: `.phpcs-report.txt`\n\n## Credits\nPeople:\n- [Dmitry Lezhnev](https://github.com/lezhnev74)\n- [Carsten Brandt](https://github.com/cebe)\n- [Samuel Nela](https://github.com/samnela)\n- [Pavel Batanov](https://github.com/scaytrase)\n- [Christopher L Bray](https://github.com/brayniverse)\n- [David Pauli](https://github.com/dpauli)\n- [Jason Judge](https://github.com/judgej)\n- [Yannick Chenot](https://github.com/osteel)\n- [TarasBK](https://github.com/TarasBK)\n- [Jason B. Standing](https://github.com/jasonbstanding)\n- [Dmytro Demchyna](https://github.com/dmytro-demchyna)\n- [Will Chambers](https://github.com/willchambers99)\n- [Ignacio](https://github.com/imefisto)\n- A big thank you to [Henrik Karlström](https://github.com/hkarlstrom) who kind of inspired me to work on this package. \n\nResources:\n- Icons made by Freepik, licensed by CC 3.0 BY\n- [cebe/php-openapi](https://github.com/cebe/php-openapi) package for Reading OpenAPI files\n- [slim3-psr15](https://github.com/bnf/slim3-psr15) package for Slim middleware adapter\n \n## License\nThe MIT License (MIT). Please see `License.md` file for more information.\n\n## TODO\n- [ ] Support Discriminator Object (note: apparently, this is not so straightforward, as discriminator can point to any external scheme)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flezhnev74%2Fopenapi-psr7-validator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flezhnev74%2Fopenapi-psr7-validator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flezhnev74%2Fopenapi-psr7-validator/lists"}