Skip to content

Commit b1b9213

Browse files
committed
Use IRIs as GraphQL's ids and improve perf
1 parent 1ad842d commit b1b9213

24 files changed

+517
-592
lines changed

features/graphql/query3.feature renamed to features/graphql/collection.feature

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Feature: GraphQL query support
1+
Feature: GraphQL collection support
22

33
@createSchema
44
@dropSchema
@@ -16,7 +16,7 @@ Feature: GraphQL query support
1616
}
1717
}
1818
}
19-
dummyGroup(id: 2) {
19+
dummyGroup(id: "/dummy_groups/2") {
2020
foo
2121
}
2222
}
@@ -239,7 +239,7 @@ Feature: GraphQL query support
239239
When I send the following GraphQL request:
240240
"""
241241
{
242-
compositePrimitiveItem(name: "Bar", year: 2017) {
242+
compositePrimitiveItem(id: "/composite_primitive_items/name=Bar;year=2017") {
243243
description
244244
}
245245
}
@@ -256,7 +256,7 @@ Feature: GraphQL query support
256256
When I send the following GraphQL request:
257257
"""
258258
{
259-
compositeRelation(compositeItem: {id: 1}, compositeLabel: {id: 1}) {
259+
compositeRelation(id: "/composite_relations/compositeItem=1;compositeLabel=1") {
260260
value
261261
}
262262
}

features/graphql/query1.feature renamed to features/graphql/introspection.feature

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Feature: GraphQL query support
1+
Feature: GraphQL introspection support
22

33
@createSchema
44
Scenario: Execute an empty GraphQL query
@@ -89,9 +89,10 @@ Feature: GraphQL query support
8989
When I send the following GraphQL request:
9090
"""
9191
{
92-
dummyItem: dummy(id: 3) {
92+
dummyItem: dummy(id: "/dummies/3") {
9393
name
9494
relatedDummy {
95+
id
9596
name
9697
__typename
9798
}

features/graphql/mutation.feature

Lines changed: 23 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -38,37 +38,34 @@ Feature: GraphQL mutation support
3838
When I send the following GraphQL request:
3939
"""
4040
mutation {
41-
createDummy(input: {name: "A new one", alias: "new", description: "brand new!"}) {
41+
createFoo(input: {name: "A new one", bar: "new"}) {
4242
id,
4343
name,
44-
alias,
45-
description
44+
bar
4645
}
4746
}
4847
"""
4948
Then the response status code should be 200
5049
And the response should be in JSON
5150
And the header "Content-Type" should be equal to "application/json"
52-
And the JSON node "data.createDummy.id" should be equal to 1
53-
And the JSON node "data.createDummy.name" should be equal to "A new one"
54-
And the JSON node "data.createDummy.alias" should be equal to "new"
55-
And the JSON node "data.createDummy.description" should be equal to "brand new!"
51+
And the JSON node "data.createFoo.id" should be equal to "/foos/1"
52+
And the JSON node "data.createFoo.name" should be equal to "A new one"
53+
And the JSON node "data.createFoo.bar" should be equal to "new"
5654

5755
@dropSchema
5856
Scenario: Delete an item through a mutation
5957
When I send the following GraphQL request:
6058
"""
6159
mutation {
62-
deleteDummy(input: {id: 1}) {
60+
deleteFoo(input: {id: "/foos/1"}) {
6361
id
6462
}
6563
}
6664
"""
67-
Then print last response
6865
Then the response status code should be 200
6966
And the response should be in JSON
7067
And the header "Content-Type" should be equal to "application/json"
71-
And the JSON node "data.deleteDummy.id" should be equal to 1
68+
And the JSON node "data.deleteFoo.id" should be equal to "/foos/1"
7269

7370
@createSchema
7471
@dropSchema
@@ -77,65 +74,52 @@ Feature: GraphQL mutation support
7774
When I send the following GraphQL request:
7875
"""
7976
mutation {
80-
deleteCompositeRelation(input: {compositeItem: {id: 1}, compositeLabel: {id: 1}}) {
81-
compositeItem {
82-
id
83-
},
84-
compositeLabel {
85-
id
86-
}
77+
deleteCompositeRelation(input: {id: "/composite_relations/compositeItem=1;compositeLabel=1"}) {
78+
id
8779
}
8880
}
8981
"""
9082
Then the response status code should be 200
9183
And the response should be in JSON
9284
And the header "Content-Type" should be equal to "application/json"
93-
And the JSON node "data.deleteCompositeRelation.compositeItem.id" should be equal to 1
94-
And the JSON node "data.deleteCompositeRelation.compositeLabel.id" should be equal to 1
85+
And the JSON node "data.deleteCompositeRelation.id" should be equal to "/composite_relations/compositeItem=1;compositeLabel=1"
9586

9687
@createSchema
9788
@dropSchema
9889
Scenario: Modify an item through a mutation
99-
Given there is 1 dummy objects
90+
Given there are 1 foo objects with fake names
10091
When I send the following GraphQL request:
10192
"""
10293
mutation {
103-
updateDummy(input: {id: 1, description: "Modified description."}) {
94+
updateFoo(input: {id: "/foos/1", bar: "Modified description."}) {
10495
id,
10596
name,
106-
description
97+
bar
10798
}
10899
}
109100
"""
110101
Then the response status code should be 200
111102
And the response should be in JSON
112103
And the header "Content-Type" should be equal to "application/json"
113-
And the JSON node "data.updateDummy.id" should be equal to 1
114-
And the JSON node "data.updateDummy.name" should be equal to "Dummy #1"
115-
And the JSON node "data.updateDummy.description" should be equal to "Modified description."
104+
And the JSON node "data.updateFoo.id" should be equal to "/foos/1"
105+
And the JSON node "data.updateFoo.name" should be equal to "Hawsepipe"
106+
And the JSON node "data.updateFoo.bar" should be equal to "Modified description."
116107

117-
# Composite identifiers are not supported yet
118108
@createSchema
119109
@dropSchema
120110
Scenario: Modify an item with composite identifiers through a mutation
121111
Given there are Composite identifier objects
122112
When I send the following GraphQL request:
123113
"""
124114
mutation {
125-
updateCompositeRelation(input: {compositeItem: {id: 2}, compositeLabel: {id: 8}, value: "Modified value."}) {
126-
compositeItem {
127-
id
128-
},
129-
compositeLabel {
130-
id
131-
},
115+
updateCompositeRelation(input: {id: "/composite_relations/compositeItem=1;compositeLabel=2", value: "Modified value."}) {
116+
id
132117
value
133118
}
134119
}
135120
"""
136-
#Then the response status code should be 200
137-
#And the response should be in JSON
138-
#And the header "Content-Type" should be equal to "application/json"
139-
#And the JSON node "data.putCompositeRelation.compositeItem.id" should be equal to 1
140-
#And the JSON node "data.putCompositeRelation.compositeLabel.id" should be equal to 1
141-
#And the JSON node "data.putCompositeRelation.value" should be equal to "Modified value."
121+
Then the response status code should be 200
122+
And the response should be in JSON
123+
And the header "Content-Type" should be equal to "application/json"
124+
And the JSON node "data.updateCompositeRelation.id" should be equal to "/composite_relations/compositeItem=1;compositeLabel=2"
125+
And the JSON node "data.updateCompositeRelation.value" should be equal to "Modified value."

features/graphql/query2.feature renamed to features/graphql/query.feature

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ Feature: GraphQL query support
66
Given there is 2 dummy objects with relatedDummy
77
When I have the following GraphQL request:
88
"""
9-
query DummyWithId($itemId: Int = 1) {
9+
query DummyWithId($itemId: ID = "/dummies/1") {
1010
dummyItem: dummy(id: $itemId) {
11+
id
1112
name
1213
relatedDummy {
14+
id
1315
name
1416
}
1517
}
@@ -18,13 +20,15 @@ Feature: GraphQL query support
1820
When I send the GraphQL request with variables:
1921
"""
2022
{
21-
"itemId": 2
23+
"itemId": "/dummies/2"
2224
}
2325
"""
2426
Then the response status code should be 200
2527
And the response should be in JSON
2628
And the header "Content-Type" should be equal to "application/json"
29+
And the JSON node "data.dummyItem.id" should be equal to "/dummies/2"
2730
And the JSON node "data.dummyItem.name" should be equal to "Dummy #2"
31+
And the JSON node "data.dummyItem.relatedDummy.id" should be equal to "/related_dummies/2"
2832
And the JSON node "data.dummyItem.relatedDummy.name" should be equal to "RelatedDummy #2"
2933

3034
@createSchema
@@ -34,23 +38,25 @@ Feature: GraphQL query support
3438
When I have the following GraphQL request:
3539
"""
3640
query DummyWithId1 {
37-
dummyItem: dummy(id: 1) {
41+
dummyItem: dummy(id: "/dummies/1") {
3842
name
3943
}
4044
}
4145
query DummyWithId2 {
42-
dummyItem: dummy(id: 2) {
46+
dummyItem: dummy(id: "/dummies/2") {
47+
id
4348
name
4449
}
4550
}
4651
"""
47-
When I send the GraphQL request with operation "DummyWithId2"
52+
And I send the GraphQL request with operation "DummyWithId2"
4853
Then the response status code should be 200
4954
And the response should be in JSON
5055
And the header "Content-Type" should be equal to "application/json"
56+
And the JSON node "data.dummyItem.id" should be equal to "/dummies/2"
5157
And the JSON node "data.dummyItem.name" should be equal to "Dummy #2"
52-
When I send the GraphQL request with operation "DummyWithId1"
53-
Then the JSON node "data.dummyItem.name" should be equal to "Dummy #1"
58+
And I send the GraphQL request with operation "DummyWithId1"
59+
And the JSON node "data.dummyItem.name" should be equal to "Dummy #1"
5460

5561
@createSchema
5662
@dropSchema
@@ -59,7 +65,7 @@ Feature: GraphQL query support
5965
When I send the following GraphQL request:
6066
"""
6167
{
62-
dummy(id: 2) {
68+
dummy(id: "/dummies/2") {
6369
name
6470
}
6571
}
@@ -83,10 +89,12 @@ Feature: GraphQL query support
8389
fragment dummyFields on DummyConnection {
8490
edges {
8591
node {
92+
id
8693
name
8794
relatedDummy {
8895
name
8996
thirdLevel {
97+
id
9098
level
9199
}
92100
}

src/Api/IriConverterInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace ApiPlatform\Core\Api;
1515

1616
use ApiPlatform\Core\Exception\InvalidArgumentException;
17+
use ApiPlatform\Core\Exception\ItemNotFoundException;
1718
use ApiPlatform\Core\Exception\RuntimeException;
1819

1920
/**
@@ -30,6 +31,7 @@ interface IriConverterInterface
3031
* @param array $context
3132
*
3233
* @throws InvalidArgumentException
34+
* @throws ItemNotFoundException
3335
*
3436
* @return object
3537
*/

src/Bridge/Doctrine/Orm/Extension/EagerLoadingExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ private function joinRelations(QueryBuilder $queryBuilder, QueryNameGeneratorInt
118118

119119
foreach ($classMetadata->associationMappings as $association => $mapping) {
120120
//Don't join if max depth is enabled and the current depth limit is reached
121-
if (isset($context[AbstractObjectNormalizer::ENABLE_MAX_DEPTH]) && 0 === $currentDepth) {
121+
if (0 === $currentDepth && isset($context[AbstractObjectNormalizer::ENABLE_MAX_DEPTH])) {
122122
continue;
123123
}
124124

src/Bridge/Symfony/Bundle/Resources/config/graphql.xml

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
<services>
88
<service id="api_platform.graphql.executor" class="ApiPlatform\Core\Graphql\Executor" public="false" />
99

10-
<service id="api_platform.graphql.collection_resolver_factory" class="ApiPlatform\Core\Graphql\Resolver\CollectionResolverFactory" public="false">
10+
<!-- Resolvers -->
11+
12+
<service id="api_platform.graphql.resolver.collection_factory" class="ApiPlatform\Core\Graphql\Resolver\CollectionResolverFactory" public="false">
1113
<argument type="service" id="api_platform.collection_data_provider" />
1214
<argument type="service" id="api_platform.subresource_data_provider" />
1315
<argument type="service" id="serializer" />
@@ -17,44 +19,61 @@
1719
<argument>%api_platform.collection.pagination.enabled%</argument>
1820
</service>
1921

20-
<service id="api_platform.graphql.item_resolver_factory" class="ApiPlatform\Core\Graphql\Resolver\ItemResolverFactory" public="false">
21-
<argument type="service" id="api_platform.item_data_provider" />
22-
<argument type="service" id="api_platform.subresource_data_provider" />
22+
<service id="api_platform.graphql.resolver.item_factory" class="ApiPlatform\Core\Graphql\Resolver\ItemResolverFactory" public="false">
23+
<argument type="service" id="api_platform.iri_converter" />
2324
<argument type="service" id="serializer" />
24-
<argument type="service" id="api_platform.identifiers_extractor.cached" />
2525
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
2626
</service>
2727

28-
<service id="api_platform.graphql.item_mutation_resolver_factory" class="ApiPlatform\Core\Graphql\Resolver\ItemMutationResolverFactory" public="false">
29-
<argument type="service" id="api_platform.identifiers_extractor.cached" />
30-
<argument type="service" id="api_platform.item_data_provider" />
28+
<service id="api_platform.graphql.resolver.item_mutation_factory" class="ApiPlatform\Core\Graphql\Resolver\ItemMutationResolverFactory" public="false">
29+
<argument type="service" id="api_platform.iri_converter" />
30+
<argument type="service" id="api_platform.data_persister" />
3131
<argument type="service" id="serializer" />
3232
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
33-
<argument type="service" id="api_platform.data_persister" />
33+
</service>
34+
35+
<service id="api_platform.graphql.resolver.resource_field" class="ApiPlatform\Core\Graphql\Resolver\ResourceFieldResolver" public="false">
36+
<argument type="service" id="api_platform.iri_converter" />
3437
</service>
3538

3639
<service id="api_platform.graphql.schema_builder" class="ApiPlatform\Core\Graphql\Type\SchemaBuilder" public="false">
3740
<argument type="service" id="api_platform.metadata.property.name_collection_factory" />
3841
<argument type="service" id="api_platform.metadata.property.metadata_factory" />
3942
<argument type="service" id="api_platform.metadata.resource.name_collection_factory" />
4043
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
41-
<argument type="service" id="api_platform.graphql.collection_resolver_factory" />
42-
<argument type="service" id="api_platform.graphql.item_resolver_factory" />
43-
<argument type="service" id="api_platform.graphql.item_mutation_resolver_factory" />
44-
<argument type="service" id="api_platform.identifiers_extractor.cached" />
44+
<argument type="service" id="api_platform.graphql.resolver.collection_factory" />
45+
<argument type="service" id="api_platform.graphql.resolver.item_factory" />
46+
<argument type="service" id="api_platform.graphql.resolver.item_mutation_factory" />
47+
<argument type="service" id="api_platform.graphql.resolver.resource_field" />
4548
<argument>%api_platform.collection.pagination.enabled%</argument>
4649
</service>
4750

4851
<!-- Action -->
4952

50-
<service id="api_platform.action.graphql_entrypoint" class="ApiPlatform\Core\Graphql\Action\EntrypointAction" public="true">
53+
<service id="api_platform.graphql.action.entrypoint" class="ApiPlatform\Core\Graphql\Action\EntrypointAction" public="true">
5154
<argument type="service" id="api_platform.graphql.schema_builder" />
5255
<argument type="service" id="api_platform.graphql.executor" />
5356
<argument type="service" id="twig" />
5457
<argument>%kernel.debug%</argument>
5558
<argument>%api_platform.graphql.graphiql.enabled%</argument>
5659
<argument>%api_platform.title%</argument>
5760
</service>
61+
62+
<!-- Serializer -->
63+
64+
<service id="api_platform.graphql.normalizer.item" class="ApiPlatform\Core\Graphql\Serializer\ItemNormalizer" public="false">
65+
<argument type="service" id="api_platform.metadata.property.name_collection_factory" />
66+
<argument type="service" id="api_platform.metadata.property.metadata_factory" />
67+
<argument type="service" id="api_platform.iri_converter" />
68+
<argument type="service" id="api_platform.resource_class_resolver" />
69+
<argument type="service" id="api_platform.property_accessor" />
70+
<argument type="service" id="api_platform.name_converter" on-invalid="ignore" />
71+
<argument type="service" id="serializer.mapping.class_metadata_factory" on-invalid="ignore" />
72+
<argument type="service" id="api_platform.item_data_provider" on-invalid="ignore" />
73+
<argument>%api_platform.allow_plain_identifiers%</argument>
74+
75+
<tag name="serializer.normalizer" priority="8" />
76+
</service>
5877
</services>
5978

6079
</container>

src/Bridge/Symfony/Bundle/Resources/config/routing/graphql.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
http://symfony.com/schema/routing/routing-1.0.xsd">
77

88
<route id="api_graphql_entrypoint" path="/graphql">
9-
<default key="_controller">api_platform.action.graphql_entrypoint</default>
9+
<default key="_controller">api_platform.graphql.action.entrypoint</default>
1010
</route>
1111

1212
</routes>

0 commit comments

Comments
 (0)