我有一个 symfony 项目,我在其中使用 api-platform。
我有一个实体,并且有它的数据提供者。我在定义集合端点的附加参数时遇到麻烦。
一个实体称为建议。它必须从弹性搜索返回文档集合。
终点是:
/suggestion
此端点监听额外的 GET 参数:
页面、级别
每次请求端点时都会读取这两个参数。
在我的
SuggestionsCollectionDataProvider.php
课程中,我有:
/**
* 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
课上:
/**
* @return \Generator
*/
public function find(int $page, int $level): \Generator
{
// here I can process with $level without problems
Page参数为默认参数,即在swagger中生成集合。
API 平台生成的 Swagger 文档的屏幕截图:
但是page参数现在是唯一可以在网页版中编辑的参数。
我需要向 swagger 添加更多参数(在本例中为
level
)并描述它们,以便用户/测试人员知道哪个参数实际到达此端点。
主要问题:如何告诉 api 平台,我希望 API 的用户/测试人员(从客户端)输入一些其他参数,例如 level
?
我还没有找到它的文档,但我找到了一种方法。
在实体类中
Suggestion.php
我添加了一些注释行:
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 平台 swagger DOC 中的结果视图:
在 services.yaml 中我添加:
App\Swagger\SwaggerEventRequireDecorator:
decorates: 'api_platform.swagger.normalizer.api_gateway'
arguments: [ '@App\Swagger\SwaggerEventRequireDecorator.inner' ]
autoconfigure: false
在 App\Swagger 文件夹中,我添加了以下类:
<?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);
}
}
注:
new GetCollection(
uriTemplate: '/products',
controller: GetProductsCollection::class,
openapiContext: [
'parameters' => [
[
'name' => 'page',
'in' => 'query',
'description' => 'Collection page number',
'required' => false,
'type' => 'integer',
'default' => 1,
],
[
'name' => 'rows',
'in' => 'query',
'description' => 'Max rows',
'required' => false,
'type' => 'integer',
'default' => 50,
],
],
],
read: false
),
* "openapi_context" = {
* "parameters" = {
* {
* "name" = "nameOfQueryParameter",
* "in" = "query",
* "description" = "Description goes here",
* "schema" = {
* "type" = "string"
* }
* }
* }
* }
"in" = "path",
https://api-platform.com/docs/core/filters/)。
例如,对于我的地址模型,我只使用 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
}
将会导致希望它可以帮助别人!
<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>
这会给你带来这个:
这将为您提供所需的 openApi 文档条目,其优点是 api-platform 还将自动应用您在过滤器类中描述的验证约束。另外,您可以使用经过净化(或未经净化)的值来丰富上下文。
<?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 平台文档中没有对此进行描述,但是,这里是当前的文档链接:
https://api-platform.com/docs/core/filters/#creating-custom-filters。
注意实现正确的接口;)
openapi_context
和
parameters
而不是
QueryParameter
:
new GetCollection(
uriTemplate: '/example/custom',
controller: ExampleCustomAction::class,
name: 'custom',
parameters: [
'param_name' => new QueryParameter(
required: true,
description: 'Param description',
schema: ['type' => 'string']
),
],
)
请注意如何声明类型:
schema: ['type' => 'string']
因此它将被正确传递给 openapi.yaml
|
openapi.json
如果您需要的话。顺便说一句,使用
openapi_context
时,您也应该使用
schema
,而不是直接使用
type
。