API 平台:如何规范化 GraphQL 中的嵌入式实体集合?
API Platform: How to normalize a collection of embedded entities in GraphQL?
我正在尝试在 GraphQL 中创建一个可选的子资源集合(带分页)。我希望能够查询:
query {
getA(id: '/api/A/1') {
aId
subresources {
totalCount
pageInfo {
endCursor
startCursor
hasNextPage
hasPreviousPage
}
edges {
node {
bId
}
}
}
}
}
并得到结果:
{
aId: 1,
subresources: {
"totalCount": XX,
"pageInfo": {
"endCursor": "MQ==",
"startCursor": "MA==",
"hasNextPage": true,
"hasPreviousPage": false
},
edges: [
{
node: {
bId: 11
}
},
{
node: {
bId: 12
}
},
{
node: {
bId: 13
}
}
]
}
}
我根本没有使用 Doctrine - 我使用的是自定义数据提供程序。我遇到的问题是,即使我 return 来自 DataProvider::getItem()
的 A
实体具有 B
子资源数组,我得到一个空数组 subresources
在 GraphQL 中。不过,我在 REST 中得到了正确的数据。
我正在按照 SymfonyCasts and I found a related API Platform issue 中给出的说明进行操作,但我仍然没有运气。
我通过 API 平台核心进行了追踪,我认为这与实体在 GraphQL 中的规范化方式有关。具体来说,在 ItemNormalizer::normalizeCollectionOfRelations()
中 returned 了一个空数组。但是,有一条评论说“to-many 由 GraphQL 解析器直接处理”,但我不确定它指的是什么。
这是实体代码。
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;
#[ApiResource(
graphql: ['item_query', 'collection_query', 'create', 'update', 'delete'],
collectionOperations: ['get', 'post'],
itemOperations: ['get', 'put', 'patch', 'delete'],
normalizationContext: ['groups' => ['read']],
denormalizationContext: ['groups' => ['write']],
)]
class A {
#[ApiProperty(identifier: true)]
#[Groups(['read', 'write'])]
public ?int $aId = null,
/** @var B[] */
#[ApiProperty(readableLink: true, writableLink: true)]
#[Groups(['read', 'write'])]
public $subresources = []
}
并且:
#[ApiResource(
graphql: ['item_query', 'collection_query', 'create', 'update', 'delete'],
collectionOperations: ['get', 'post'],
itemOperations: ['get', 'put', 'patch', 'delete'],
normalizationContext: ['groups' => ['read']],
denormalizationContext: ['groups' => ['write']],
)]
class B {
#[ApiProperty(identifier: true)]
#[Groups(['read', 'write'])]
public ?int $bId = null,
}
我的 ADataProvider:
public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): A {
$bs = $this->bDataProvider->getCollection(B::class, null, []);
return new A(123, $bs);
}
我的 BDataProvider:
/**
* @return ArrayPaginator<B>
*/
public function getCollection(string $resourceClass, string $operationName = null, array $context = []): ArrayPaginator {
return ArrayPaginator::fromList([new B(11), new B(12), new B(13)]);
}
ArrayPaginator
实现了 IteratorAggregate
和 PaginatorInterface
.
具体来说,我看到了这个错误:
{
"errors": [
{
"debugMessage": "Collection returned by the collection data provider must implement ApiPlatform\Core\DataProvider\PaginatorInterface or ApiPlatform\Core\DataProvider\PartialPaginatorInterface.",
"message": "Internal server error",
"extensions": {
"category": "internal"
},
"locations": [
{
"line": 29,
"column": 5
}
],
"path": [
"a",
"b"
],
"trace": [
{
"file": "/homedir/core/src/GraphQl/Resolver/Stage/SerializeStage.php",
"line": 100,
"call": "ApiPlatform\Core\GraphQl\Resolver\Stage\SerializeStage::serializeCursorBasedPaginatedCollection(array(0), array(5), array(6))"
},
TLDR:如何使用注释(或 YAML)使作为子资源集合的属性在 GraphQL 中可选?
各位help/ideas不胜感激,感谢阅读!
找到解决方案:ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface
需要由BDataProvider
实现。
它在 api 平台的 graphql 解析器的 ReadStage 中使用。令人惊讶的是,它在 REST 解析器中找不到任何地方,所以它不会在 REST 请求中被调用。
唯一需要实施的方法是getSubresource()
。我的第一个基本实现如下所示:
public function getSubresource(string $resourceClass, array $identifiers, array $context, string $operationName = null) {
if ($context['collection']) {
return $this->getCollection($resourceClass, $operationName, $context);
}
$id = // get your id from $identifiers;
return $this->getItem($resourceClass, $id, $operationName, $context);
}
我正在尝试在 GraphQL 中创建一个可选的子资源集合(带分页)。我希望能够查询:
query {
getA(id: '/api/A/1') {
aId
subresources {
totalCount
pageInfo {
endCursor
startCursor
hasNextPage
hasPreviousPage
}
edges {
node {
bId
}
}
}
}
}
并得到结果:
{
aId: 1,
subresources: {
"totalCount": XX,
"pageInfo": {
"endCursor": "MQ==",
"startCursor": "MA==",
"hasNextPage": true,
"hasPreviousPage": false
},
edges: [
{
node: {
bId: 11
}
},
{
node: {
bId: 12
}
},
{
node: {
bId: 13
}
}
]
}
}
我根本没有使用 Doctrine - 我使用的是自定义数据提供程序。我遇到的问题是,即使我 return 来自 DataProvider::getItem()
的 A
实体具有 B
子资源数组,我得到一个空数组 subresources
在 GraphQL 中。不过,我在 REST 中得到了正确的数据。
我正在按照 SymfonyCasts and I found a related API Platform issue 中给出的说明进行操作,但我仍然没有运气。
我通过 API 平台核心进行了追踪,我认为这与实体在 GraphQL 中的规范化方式有关。具体来说,在 ItemNormalizer::normalizeCollectionOfRelations()
中 returned 了一个空数组。但是,有一条评论说“to-many 由 GraphQL 解析器直接处理”,但我不确定它指的是什么。
这是实体代码。
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;
#[ApiResource(
graphql: ['item_query', 'collection_query', 'create', 'update', 'delete'],
collectionOperations: ['get', 'post'],
itemOperations: ['get', 'put', 'patch', 'delete'],
normalizationContext: ['groups' => ['read']],
denormalizationContext: ['groups' => ['write']],
)]
class A {
#[ApiProperty(identifier: true)]
#[Groups(['read', 'write'])]
public ?int $aId = null,
/** @var B[] */
#[ApiProperty(readableLink: true, writableLink: true)]
#[Groups(['read', 'write'])]
public $subresources = []
}
并且:
#[ApiResource(
graphql: ['item_query', 'collection_query', 'create', 'update', 'delete'],
collectionOperations: ['get', 'post'],
itemOperations: ['get', 'put', 'patch', 'delete'],
normalizationContext: ['groups' => ['read']],
denormalizationContext: ['groups' => ['write']],
)]
class B {
#[ApiProperty(identifier: true)]
#[Groups(['read', 'write'])]
public ?int $bId = null,
}
我的 ADataProvider:
public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): A {
$bs = $this->bDataProvider->getCollection(B::class, null, []);
return new A(123, $bs);
}
我的 BDataProvider:
/**
* @return ArrayPaginator<B>
*/
public function getCollection(string $resourceClass, string $operationName = null, array $context = []): ArrayPaginator {
return ArrayPaginator::fromList([new B(11), new B(12), new B(13)]);
}
ArrayPaginator
实现了 IteratorAggregate
和 PaginatorInterface
.
具体来说,我看到了这个错误:
{
"errors": [
{
"debugMessage": "Collection returned by the collection data provider must implement ApiPlatform\Core\DataProvider\PaginatorInterface or ApiPlatform\Core\DataProvider\PartialPaginatorInterface.",
"message": "Internal server error",
"extensions": {
"category": "internal"
},
"locations": [
{
"line": 29,
"column": 5
}
],
"path": [
"a",
"b"
],
"trace": [
{
"file": "/homedir/core/src/GraphQl/Resolver/Stage/SerializeStage.php",
"line": 100,
"call": "ApiPlatform\Core\GraphQl\Resolver\Stage\SerializeStage::serializeCursorBasedPaginatedCollection(array(0), array(5), array(6))"
},
TLDR:如何使用注释(或 YAML)使作为子资源集合的属性在 GraphQL 中可选?
各位help/ideas不胜感激,感谢阅读!
找到解决方案:ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface
需要由BDataProvider
实现。
它在 api 平台的 graphql 解析器的 ReadStage 中使用。令人惊讶的是,它在 REST 解析器中找不到任何地方,所以它不会在 REST 请求中被调用。
唯一需要实施的方法是getSubresource()
。我的第一个基本实现如下所示:
public function getSubresource(string $resourceClass, array $identifiers, array $context, string $operationName = null) {
if ($context['collection']) {
return $this->getCollection($resourceClass, $operationName, $context);
}
$id = // get your id from $identifiers;
return $this->getItem($resourceClass, $id, $operationName, $context);
}