如何使用 swagger 文档在 api-platform 的端点请求额外的 GET 参数?

How to ask for additional GET parameters in an endpoint of api-platform using swagger docs?

我有一个 symfony 项目,我在其中使用 api-platform.

我有一个实体,我有它的数据提供者。我在为 collection 端点定义附加参数时遇到了麻烦。

实体称为建议。它必须 return collection 个来自弹性搜索的文档。

端点是:

/suggestion

此端点侦听其他 GET 参数:

page, level

每次请求端点时,都会读取这两个参数。

在我的 SuggestionsCollectionDataProvider.php class 我有:

/**
     * Retrieves a collection.
     *
     * @param string $resourceClass
     * @param string|null $operationName
     * @return \Generator
     */
    public function getCollection(string $resourceClass, string $operationName = null): \Generator
    {
        $query = $this->requestStack->getCurrentRequest()->query;
        // I am reading these two parameters from RequestStack
        
        // this one is built-in
        $page = max($query->get('page', 1), 1); 

        // this is a custom one
        $level = $query->get('level', 0); 
        ...

在我的 SuggestionRepository.php class:

/**
     * @return \Generator
     */
    public function find(int $page, int $level): \Generator
    {
        // here I can process with $level without problems

Page参数为默认参数,即swagger生成collections.

API 平台生成的 Swagger 文档的屏幕截图:

但是页面参数现在是唯一可以在网页版中编辑的参数

我需要向 swagger 添加更多参数(在本例中为 level)并描述它们,因此 user/tester 知道实际使用哪个参数这个端点。

主要问题:

如何告诉 api-platform,我想要 API 的 user/tester(从客户端)输入一些其他参数,即 level例如?

终于想通了。

我还没有找到它的文档,但我找到了方法。

在实体中 class Suggestion.php 我添加了一些行 annotations:

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Class Suggestion. Represents an entity for an item from the suggestion result set.
 * @package App\Entity
 * @ApiResource(
 *     collectionOperations={
 *          "get"={
 *              "method"="GET",
 *              "swagger_context" = {
 *                  "parameters" = {
 *                      {
 *                          "name" = "level",
 *                          "in" = "query",
 *                          "description" = "Levels available in result",
 *                          "required" = "true",
 *                          "type" : "array",
 *                          "items" : {
 *                              "type" : "integer"
 *                          }
 *                      }
 *                  }
 *               }
 *          }
 *     },
 *     itemOperations={"get"}
 * )
 */

API platform swagger 文档中的结果视图:

在 Api 平台核心版本 2.4.6 中,将 "swagger_context" 添加到 get 注释对我不起作用。相反,我使用了提供的说明 API Platform - Overriding the OpenAPI Specification

就我而言,我不得不稍微偏离说明。在覆盖的规范化方法中,我必须先删除现有参数,然后将自定义定义添加到 $doc 参数数组。正如 pedrouan 所做的那样,我能够添加 required=true 属性 并且它以相同的方式工作。

在services.yaml中我添加了:

    App\Swagger\SwaggerEventRequireDecorator:
         decorates: 'api_platform.swagger.normalizer.api_gateway'
         arguments: [ '@App\Swagger\SwaggerEventRequireDecorator.inner' ]
         autoconfigure: false

在 App\Swagger 文件夹中,我添加了以下 class:

<?php

namespace App\Swagger;

use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

final class SwaggerEventRequireDecorator implements NormalizerInterface
{
    private $decorated;

    public function __construct(NormalizerInterface $decorated)
    {
        $this->decorated = $decorated;
    }

    public function normalize($object, $format = null, array $context = [])
    {
        $docs = $this->decorated->normalize($object, $format, $context);

        $customDefinition = [
            'name' => 'event',
            'description' => 'ID of the event the activities belong to.',
            'in' => 'query',
            'required' => 'true',
            'type' => 'integer'
        ];

//         e.g. remove an existing event parameter
        $docs['paths']['/scheduleamap-api/activities']['get']['parameters'] = array_values(array_filter($docs['paths']['/scheduleamap-api/activities']['get']['parameters'], function ($param) {
            return $param['name'] !== 'event';
        }));

    // e.g. add the new definition for event
    $docs['paths']['/scheduleamap-api/activities']['get']['parameters'][] = $customDefinition;

        // Remove other restricted parameters that will generate errors.
        $docs['paths']['/scheduleamap-api/activities']['get']['parameters'] = array_values(array_filter($docs['paths']['/scheduleamap-api/activities']['get']['parameters'], function ($param) {
            return $param['name'] !== 'event[]';
        }));

        return $docs;
    }

    public function supportsNormalization($data, $format = null)
    {
        return $this->decorated->supportsNormalization($data, $format);
    }
}

注:

  1. 我还在 services.yaml 中将 autowire 和 autoconfig 设置为 true。

  2. 我添加了一个自定义数据提供程序,要求在对 activity 实体资源的所有 api 请求中设置事件 属性 过滤器。上面的自定义在直接fetch或者urlget请求的时候不需要设置。

如果有人需要做类似的事情,但使用 XML 配置:

<collectionOperation name="find_duplicated_items">
    <attribute name="method">GET</attribute>
    <attribute name="path">/items/find_duplicates</attribute>
    <attribute name="controller">App\Infrastructure\Http\Items\FindDuplicates</attribute>

     <attribute name="openapi_context">
        <attribute name="parameters">

            <attribute>
                <attribute name="name">someProperty</attribute>
                <attribute name="in">query</attribute>
                <attribute name="required">true</attribute>
                <attribute name="description">List foos and bars</attribute>
                <attribute name="schema">
                     <attribute name="type">array</attribute>
                     <attribute name="items">
                        <attribute name="type">integer</attribute>
                     </attribute>
                </attribute>
            </attribute>
        
            <attribute>
                <attribute name="name">ageDays</attribute>
                <attribute name="in">query</attribute>
                <attribute name="required">false</attribute>
                <attribute name="description">Max age in days</attribute>
                <attribute name="default">5</attribute>
                <attribute name="schema">
                    <attribute name="type">integer</attribute>
                </attribute>
            </attribute>
        </attribute>

    </attribute>

</collectionOperation>

这让你:

如果有人期望在 URL 中有一个额外的 GET 参数,例如如果您的路由 {id} 参数没有被 swagger 测试工具解析,您应该在@pedrouan 中更改它解决方案:

"in" = "path",

使用 openapi_context 并参考 OpenAPI 文档:

 *              "openapi_context" = {
 *                  "parameters" = {
 *                      {
 *                          "name" = "nameOfQueryParameter",
 *                          "in" = "query",
 *                          "description" = "Description goes here",
 *                          "schema" = {
 *                              "type" = "string"
 *                          }
 *                      }
 *                  }
 *               }

您最好创建一个自定义过滤器来描述附加参数。

这将为您提供所需的 openApi 文档条目,优点是 api-platform 还将自动应用您在过滤器 class 中描述的验证约束。此外,您还可以使用经过清理(或未经清理)的值来丰富上下文。

<?php

namespace App\Filter;

use ApiPlatform\Core\Serializer\Filter\FilterInterface;
use Symfony\Component\HttpFoundation\Request;

class MyParamFilter implements FilterInterface
{
    public const MYPARAM_FILTER_CONTEXT = 'myparam';

    public function getDescription(string $resourceClass): array
    {
        $doc = [
            'allowEmptyValue' => false,
            'example' => 'blabla',
        ];
        $schema = [
            'type' => 'string',
            'minLength' => 2,
            'maxLength' => 32,
        ];

        return [
            'myparam' => [
                'description' => 'Parameter description',
                'property' => null,
                'type' => 'string',
                'required' => true,
                'swagger' => array_merge(
                    $doc,
                    $schema
                ),
                'openapi' => array_merge(
                    $doc,
                    [
                        'schema' => $schema,
                    ]
                ),
            ],
        ];
    }

    public function apply(Request $request, bool $normalization, array $attributes, array &$context): void
    {
        $context[self::MYPARAM_FILTER_CONTEXT] = $request->query->get('myparam');
    }
}

这在 api 平台文档中没有描述,但是,这里是当前文档 link:

https://api-platform.com/docs/core/filters/#creating-custom-filters.

注意实现正确的接口 ;)

您可以像在 ApiPlatform 文档 (https://api-platform.com/docs/core/filters/) 中看到的那样使用 Filter。

例如,对于我的地址模型,我只使用来自 ApiPlatform 核心的学说桥 SearchFilter

/**
 * Class Address
 *
 * @ORM\Entity
 */
#[ApiResource]
#[ApiFilter(SearchFilter::class, properties: ['street' => 'partial'])]
class Address
{
    /**
     * @var string|null $street
     *
     * @ORM\Column(type="string", nullable=true)
     */
    private ?string $street;

   // Do some fancy things here
}

它会导致

希望对大家有所帮助!