lezhnev74 / openapi-psr7-validator
Requires
- php: >=7.1
- ext-json: *
- cebe/php-openapi: ^1.2
- psr/cache: ^1.0
- psr/http-message: ^1.0
- psr/http-server-middleware: ^1.0
- respect/validation: ^1.1
- riverline/multipart-parser: ^2.0.3
- webmozart/assert: ^1.4
Requires (Dev)
- cache/array-adapter: ^1.0
- doctrine/coding-standard: ^6.0
- guzzlehttp/psr7: ^1.5
- phpunit/phpunit: ^7|^8
- dev-master
- 0.16
- 0.15.5
- 0.15.4
- 0.15.3
- 0.15.2
- 0.15.1
- 0.15.0
- 0.14.2
- 0.14.1
- 0.14.0
- 0.13.9
- 0.13.8
- 0.13.7
- 0.13.6
- 0.13.5
- 0.13.4
- 0.13.3
- 0.13.2
- 0.13.1
- 0.13.0
- 0.12.0
- 0.11.4
- 0.11.3
- 0.11.2
- 0.11.1
- 0.11.0
- 0.10.3
- 0.10.2
- 0.10.1
- 0.10.0
- 0.9.0
- 0.8.0
- 0.7.0
- 0.6.0
- 0.5.3
- 0.5.2
- 0.5.1
- 0.5.0
- dev-62-url-parameters-ints
- dev-44-improve-body-multipart-validation
This package is auto-updated.
Last update: 2019-09-19 17:17:56 UTC
README
注意 - 此包已贡献给PHP League
前往https://github.com/thephpleague/openapi-psr7-validator
此包仅面向现有用户。
OpenAPI PSR-7消息(HTTP请求/响应)验证器
此包可以验证PSR-7消息是否符合以YAML或JSON格式表达的OpenAPI(3.0.x)规范。
安装
composer require lezhnev74/openapi-psr7-validator
OpenAPI(OAS)术语
在包中使用了某些特定术语。这些术语来自OpenAPI
specification
- 描述API的OpenAPI文档,以JSON或YAML文件表达data
- 实际验证规范的东西,包括正文和元数据schema
- 规范中描述请求/响应正文的 部分keyword
- 用于描述实例的属性称为关键字,或称为模式关键字path
- 到单个端点的相对路径operation
- 应用在路径上的方法(如get /password
)response
- 描述的响应(包括状态码、内容类型等)
如何验证
ServerRequest消息
您可以通过这种方式验证\Psr\Http\Message\ServerRequestInterface
实例
$yamlFile = "api.yaml"; $jsonFile = "api.json"; $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromYamlFile($yamlFile)->getServerRequestValidator(); #or $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromYaml(file_get_contents($yamlFile))->getServerRequestValidator(); #or $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromJson(file_get_contents($jsonFile))->getServerRequestValidator(); #or $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromJsonFile($jsonFile)->getServerRequestValidator(); #or $schema = new \cebe\openapi\spec\OpenApi(); // generate schema object by hand $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromSchema($schema)->getServerRequestValidator(); $match = $validator->validate($request);
结果您将获得一个OperationAddress $match
,它匹配了给定的请求。如果您已经知道应该匹配您请求的操作(即您的项目中已有路由),则可以使用RouterRequestValidator
$address = new \OpenAPIValidation\PSR7\OperationAddress('/some/operation', 'post'); $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromSchema($schema)->getRoutedRequestValidator(); $validator->validate($address, $request);
这将大大简化验证并提高性能。
请求消息
您可以按这种方式验证\Psr\Http\Message\RequestInterface
实例
$yamlFile = "api.yaml"; $jsonFile = "api.json"; $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromYamlFile($yamlFile)->getRequestValidator(); #or $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromYaml(file_get_contents($yamlFile))->getRequestValidator(); #or $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromJson(file_get_contents($jsonFile))->getRequestValidator(); #or $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromJsonFile($jsonFile)->getRequestValidator(); #or $schema = new \cebe\openapi\spec\OpenApi(); // generate schema object by hand $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromSchema($schema)->getRequestValidator(); $match = $validator->validate($request);
响应消息
\Psr\Http\Message\ResponseInterface
的验证稍微复杂一些。因为您不仅需要YAML文件和响应本身,还需要知道这个响应属于哪个操作(在OpenAPI术语中)。
示例
$yamlFile = "api.yaml"; $jsonFile = "api.json"; $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromYamlFile($yamlFile)->getResponseValidator(); #or $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromYaml(file_get_contents($yamlFile))->getResponseValidator(); #or $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromJson(file_get_contents($jsonFile))->getResponseValidator(); #or $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromJsonFile($jsonFile)->getResponseValidator(); #or $schema = new \cebe\openapi\spec\OpenApi(); // generate schema object by hand $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromSchema($schema)->getResponseValidator(); $operation = new \OpenAPIValidation\PSR7\OperationAddress('/password/gen', 'get') ; $validator->validate($operation, $request);
验证后重用模式
\OpenAPIValidation\PSR7\ValidatorBuilder
将模式读取和编译到内存中,作为\cebe\openapi\spec\OpenApi
的实例。验证器使用此实例执行验证逻辑。您可以在验证后像这样重用此实例
$validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromYamlFile($yamlFile)->getServerRequestValidator(); # or $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder)->fromYamlFile($yamlFile)->getResponseValidator(); /** @var \cebe\openapi\spec\OpenApi */ $openApi = $validator->getSchema();
请求消息
\Psr\Http\Message\RequestInterface
验证尚未实现。
PSR-15 中间件
PSR-15 中间件可以使用如下方式:
$yamlFile = 'api.yaml'; $jsonFile = 'api.json'; $psr15Middleware = (new \OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromYamlFile($yamlFile)->getValidationMiddleware(); #or $psr15Middleware = (new \OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromYaml(file_get_contents($yamlFile))->getValidationMiddleware(); #or $psr15Middleware = (new \OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromJsonFile($jsonFile)->getValidationMiddleware(); #or $psr15Middleware = (new \OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromJson(file_get_contents($jsonFile))->getValidationMiddleware(); #or $schema = new \cebe\openapi\spec\OpenApi(); // generate schema object by hand $validator = (new \OpenAPIValidation\PSR7\ValidationMiddlewareBuilder)->fromSchema($schema)->getValidationMiddleware();
SlimFramework 中间件
Slim 框架使用略有不同的中间件接口,因此这里有一个适配器,您可以像这样使用:
$yamlFile = 'api.yaml'; $jsonFile = 'api.json'; $psr15Middleware = (new \OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromYamlFile($yamlFile)->getValidationMiddleware(); #or $psr15Middleware = (new \OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromYaml(file_get_contents($yamlFile))->getValidationMiddleware(); #or $psr15Middleware = (new \OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromJsonFile($jsonFile)->getValidationMiddleware(); #or $psr15Middleware = (new \OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromJson(file_get_contents($jsonFile))->getValidationMiddleware(); #or $schema = new \cebe\openapi\spec\OpenApi(); // generate schema object by hand $validator = (new \OpenAPIValidation\PSR7\ValidationMiddlewareBuilder)->fromSchema($schema)->getValidationMiddleware(); $slimMiddleware = new \OpenAPIValidation\PSR15\SlimAdapter($psr15Middleware); /** @var \Slim\App $app */ $app->add($slimMiddleware);
缓存层 / PSR-6 支持
PSR-7 验证器内置了一个缓存层(基于 PSR-6 接口),它可以在解析 OpenAPI 规范时节省时间。这是可选的。您可以通过将配置好的缓存池对象传递给静态构造函数来启用缓存,如下所示:
// Configure a PSR-6 Cache Pool $cachePool = new ArrayCachePool(); // Pass it as a 2nd argument $validator = (new \OpenAPIValidation\PSR7\ValidatorBuilder) ->fromYamlFile($yamlFile) ->setCache($cachePool) ->getResponseValidator(); # or \OpenAPIValidation\PSR15\ValidationMiddleware::fromYamlFile($yamlFile, $cachePool);
您可以使用 ->setCache($pool, $ttl)
调用为 PSR-7 和 PSR-15 构建器设置适当的过期时间(以秒为单位或显式 null
)。
如果您想控制模式项的缓存键,或者您的缓存不支持自动生成缓存键,您可以通过 ->overrideCacheKey('my_custom_key')
确保缓存使用您想要的键。
独立 OpenAPI 验证器
该软件包包含一个独立验证器,可以像这样验证任何数据与 OpenAPI 模式:
$spec = <<<SPEC schema: type: string enum: - a - b SPEC; $data = "c"; $spec = cebe\openapi\Reader::readFromYaml($spec); # (optional) reference resolving $spec->resolveReferences(new ReferenceContext($spec, "/")); $schema = new cebe\openapi\spec\Schema($spec->schema); try { (new \OpenAPIValidation\Schema\SchemaValidator())->validate($data, $schema); } catch(\OpenAPIValidation\Schema\Exception\KeywordMismatch $e) { // you can evaluate failure details // $e->keyword() == "enum" // $e->data() == "c" // $e->dataBreadCrumb()->buildChain() -- only for nested data }
自定义类型格式
如您所知,OpenAPI 允许您向类型添加格式
schema: type: string format: binary
此软件包包含一系列内置格式验证器
string
类型字节
日期
日期时间
电子邮件
主机名
IPv4
IPv6
URI
uuid
(uuid4)
number
类型浮点数
双精度浮点数
您还可以添加自己的格式。例如:
# 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 \OpenAPIValidation\Schema\TypeFormats\FormatsContainer::registerFormat('string', 'custom', $customFormat);
异常
该软件包会抛出一系列异常,您可以捕获并处理。以下是一些异常:
- 与模式相关的异常
\OpenAPIValidation\Schema\Exception\KeywordMismatch
- 表示数据未与模式的关键字匹配\OpenAPIValidation\Schema\Exception\TypeMismatch
- 对type
关键字的验证失败。例如,type:string
和值是12
\OpenAPIValidation\Schema\Exception\FormatMismatch
- 数据与给定的类型格式不匹配。例如,type: string, format: email
不会匹配not-email
。
- 与 PSR7 消息相关的异常
\OpenAPIValidation\PSR7\Exception\NoContentType
- HTTP 消息(请求/响应)不包含 Content-Type 标头。一般 HTTP 错误。\OpenAPIValidation\PSR7\Exception\NoPath
- 路径未在规范中找到\OpenAPIValidation\PSR7\Exception\NoOperation
- 路径中未找到操作\OpenAPIValidation\PSR7\Exception\NoResponseCode
- 规范中未找到操作下的响应代码- 验证异常(检查父异常以获取可能的根本原因)
\OpenAPIValidation\PSR7\Exception\ValidationFailed
- 失败的 PSR-7 消息的通用异常\OpenAPIValidation\PSR7\Exception\Validation\InvalidBody
- 主体与模式不匹配\OpenAPIValidation\PSR7\Exception\Validation\InvalidCookies
- 饼干与模式不匹配或缺少必需的饼干\OpenAPIValidation\PSR7\Exception\Validation\InvalidHeaders
- 标头与模式不匹配或缺少必需的标头\OpenAPIValidation\PSR7\Exception\Validation\InvalidPath
- 路径不匹配模式或模式值不匹配模式\OpenAPIValidation\PSR7\Exception\Validation\InvalidQueryArgs
- 查询参数与模式不匹配或缺少必需参数\OpenAPIValidation\PSR7\Exception\Validation\InvalidSecurity
- 请求与安全模式不匹配或安全头无效
- 请求相关
\OpenAPIValidation\PSR7\Exception\MultipleOperationsMismatchForRequest
- 请求与规范中的多个操作匹配,但所有验证均失败。
测试
您可以使用以下命令运行测试
vendor/bin/phpunit
贡献指南
欢迎提交问题或添加Pull request。此包遵循以下代码风格: doctrine/coding-standard。
为了符合此风格,请使用此包附带的git钩子,位于.githooks/pre-commit
。
如何使用它
- 在本地克隆包并导航到该文件夹
- 创建一个指向钩子的符号链接,例如:
ln -s -f ../../.githooks/pre-commit .git/hooks/pre-commit
- 添加执行权限:
chmod +x .git/hooks/pre-commit
- 现在提交任何新更改,代码将被相应地检查和格式化。
- 如果代码有任何问题,请在此处检查日志:
.phpcs-report.txt
鸣谢
人员
- Dmitry Lezhnev
- Carsten Brandt
- Samuel Nela
- Pavel Batanov
- Christopher L Bray
- David Pauli
- Jason Judge
- Yannick Chenot
- TarasBK
- Jason B. Standing
- Dmytro Demchyna
- Will Chambers
- Ignacio
- 特别感谢 Henrik Karlström,他的灵感激发了我开发此包。
资源
- 图标由Freepik制作,许可协议为CC 3.0 BY
- cebe/php-openapi 包用于读取OpenAPI文件
- slim3-psr15 包用于Slim中间件适配器
许可证
MIT许可证(MIT)。有关更多信息,请参阅License.md
文件。
待办事项
- 支持Discriminator Object(注意:显然,这并不简单,因为discriminator可以指向任何外部模式)