如何使用 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);
}
}
注:
我还在 services.yaml 中将 autowire 和 autoconfig 设置为 true。
我添加了一个自定义数据提供程序,要求在对 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
}
它会导致
希望对大家有所帮助!
我有一个 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);
}
}
注:
我还在 services.yaml 中将 autowire 和 autoconfig 设置为 true。
我添加了一个自定义数据提供程序,要求在对 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
}
它会导致
希望对大家有所帮助!