synatos/porta

该包的最新版本(0.1.3)没有提供许可证信息。

OpenAPI 3.0 验证

0.1.3 2024-03-15 10:10 UTC

This package is not auto-updated.

Last update: 2024-09-27 12:39:54 UTC


README

Porta 是希腊语,意为门。该项目可以用作 Rest API 端点的门。Open API 标准允许精确描述 REST API 中的信息在服务器进入和离开时的内容。该标准可用于:1. 使用 Swagger 等工具描述接口/文档 2. 验证传入和传出的 REST 消息 3. 生成请求/响应类,允许将未类型化的数组/json 转换为类型化对象。

描述

Porta 是一个 Open API 3.0 架构验证器,用于 Http 请求。本实现的特色功能:

  • 验证 JSON 请求和响应
  • 使用对象操作/构建 Open API 架构
  • 注册自己的格式验证器
  • 为给定的架构生成请求和响应类
  • 将 Open API 架构编译为类。

安装

composer require synatos/porta

导入/导出

您可以轻松导入/导出 JSON/Yaml 文件

use Synatos\Porta\Model\OpenAPI;

$openAPI = new OpenAPI();

# yaml
$openAPI->fromYamlFile(__DIR__ . "/my-open-api.yml");
$openAPI->toYamlFile(__DIR__ . "/export.yml");

# json
$openAPI->fromJSONFile("my-open-api.json");
$openAPI->toJSONFile(__DIR__ . "/export.json");

验证

请求验证

请求可以轻松地与给定的架构进行验证。重要提示:请确保请求内容的类型已在 HTTP 标头中设置。Open API 允许多种工件进行验证

  • 查询参数
  • 路由参数
  • HTTP 头部
  • Cookie
  • 请求体

以下示例显示了如何使用 Open API 架构验证 HTTP 请求。

use Synatos\Porta\Http\ContentType;
use Synatos\Porta\Http\HttpHeader;
use Synatos\Porta\Model\OpenAPI;
use Synatos\Porta\Porta;

require_once '../vendor/autoload.php';

$openAPI = new OpenAPI();
$openAPI->fromJSONFile(__DIR__ . '/open-api.json');

$porta = new Porta();
$porta->setOpenAPI($openAPI);

$path = "/api/security/login-with-password";
$method = "POST";
$header = [
    HttpHeader::CONTENT_TYPE => ContentType::APPLICATION_JSON
];
$query = [];

$requestBody = json_encode([
    "email" => "email@email.com",
    "password" => "abcd1234"
]);

$validationMessageList = $porta->validateRequest($path, $method, $header,$query, $requestBody);

注册自己的格式验证器

Open API 规范允许定义格式来更详细地指定数据类型

"然而,格式是一个开放值,因此您可以使用任何格式,甚至不是由 OpenAPI 规范定义的格式,例如:"(来源 https://swagger.org.cn/docs/specification/data-models/data-types/#string

使用 Porta,您可以注册自己的验证器来处理格式。以下是一个示例

use Synatos\Porta\Contract\Validator;
use Synatos\Porta\Http\ContentType;
use Synatos\Porta\Http\HttpHeader;
use Synatos\Porta\Model\OpenAPI;
use Synatos\Porta\Model\Schema;
use Synatos\Porta\Porta;
use Synatos\Porta\Validator\FormatValidatorFactory;

require_once '../vendor/autoload.php';

class EmailValidator implements Validator
{
    public function validate(Schema $schema, $value, array $propertyPath): array
    {
        echo "validating " . $value . PHP_EOL;
        return [];
    }
}

FormatValidatorFactory::addFormatValidator("email", new EmailValidator());

从架构生成 PHP 类

架构会变得越来越大,解析 json/yaml 包括文件加载可能会变得耗时。因此,可以将现有架构编译成一个包含架构数组内联的类

use Synatos\Porta\Generator\OpenAPIClassGenerator;
use Synatos\Porta\Model\OpenAPI;

require_once '../vendor/autoload.php';

$openAPI = new OpenAPI();
$openAPI->fromJSONFile(__DIR__ . '/open-api.json');

$fullyQualifiedClassName = "Example\\CompiledSchema";
$psrPrefix = "";
$baseDir = __DIR__;

$openAPIClassGenerator = new OpenAPIClassGenerator();
$openAPIClassGenerator->generate($openAPI, $fullyQualifiedClassName, $psrPrefix, $baseDir);

此编译的类将包含以下内容

class CompiledSchema
{

    /**
     * @var OpenAPI
     */
    private static $openAPI;

    /**
     * 
     * @return OpenAPI
     */
    public static function getOpenAPI() : OpenAPI
    {
        if (self::$openAPI === null) {
            self::$openAPI = new OpenAPI();
            self::$openAPI->fromArray([ /* schema will be compiled into an array */]);
        }
        return self::$openAPI;
    }
}

生成 Open API 类

您可以为给定的架构生成一个包含所有类型属性的类。此外,两个方法 \JsonSerializablefromArray(array $data) 允许从数组中初始化并再次生成数组。这样,您就不需要访问数组了,而是可以从数组中创建 Schema 对象,并以完全类型化的方式与对象一起工作。

$schemaContent = json_decode(file_get_contents(__DIR__ . '/request-schema.json'), true);

$schema = new Schema();
$schema->fromArray($schemaContent);

$psrPrefix = "";
$baseDir = __DIR__;
$namespace = "Example";
$className = "UserRequest";

$generator = new SchemaToPHPGenerator($psrPrefix, $baseDir);
$generator->generateSchema($namespace, $className, $schema);

// see example/compile-schema-class.php

生成的类将如下所示

class UserRequest implements \JsonSerializable
{

    /**
     * @var string
     */
    protected $id;
    
    /**
     * @param string|null $id
     * 
     * @return void
     */
    public function setId(?string $id)
    {
        $this->id = $id;
    }

    /**
     * 
     * @return string|null
     */
    public function getId() : ?string
    {
        return $this->id;
    }
    
    /**
     * @param array $array
     * 
     * @return void
     */
    public function fromArray(array $array) {/* ... */}
    
    
    /**
     * 
     * @return array
     */
    public function jsonSerialize() : array {/* ... */}

模型操作

Open API 中的每个工件都有一个对象表示。因此,您可以轻松构建 Schema、操作或其他任何部分

use Synatos\Porta\Http\ContentType;
use Synatos\Porta\Model\MediaType;
use Synatos\Porta\Model\OpenAPI;
use Synatos\Porta\Model\Operation;
use Synatos\Porta\Model\PathItem;
use Synatos\Porta\Model\RequestBody;
use Synatos\Porta\Model\Schema;

require_once '../vendor/autoload.php';


$intSchema = new Schema();
$intSchema->setType(Schema::TYPE_INTEGER);
$intSchema->setNullable(false);

$objectSchema = new Schema();
$objectSchema->setNullable(true);
$objectSchema->setProperties([
    "intProperty" => $intSchema
]);

$requestMediaType = new MediaType();
$requestMediaType->setSchema($objectSchema);

$requestBody = new RequestBody();
$requestBody->setRequired(true);
$requestBody->setContent([
    ContentType::APPLICATION_JSON => $requestMediaType
]);


$operation = new Operation();
$operation->setRequestBody($requestBody);

$pathItem = new PathItem();
$pathItem->setOperationByMethod(PathItem::METHOD_POST, $operation);

$openAPI = new OpenAPI();
$openAPI->setPaths([
    "/api/do/something" => $pathItem
]); 

进一步阅读