Skip to content

Commit

Permalink
[GraphQL] Services Refactoring (#2772)
Browse files Browse the repository at this point in the history
* Add a TypeConverter to manage custom types

* Fix PHPStan
  • Loading branch information
alanpoulain committed May 12, 2019
1 parent 1d5f020 commit 796f613
Show file tree
Hide file tree
Showing 25 changed files with 2,392 additions and 795 deletions.
2 changes: 1 addition & 1 deletion features/graphql/collection.feature
Expand Up @@ -113,7 +113,7 @@ Feature: GraphQL collection support
And the response should be in JSON
And the header "Content-Type" should be equal to "application/json"
And the JSON node "data.dummies.edges[1].node.name" should be equal to "Dummy #2"
And the JSON node "data.dummies.edges[1].node.dummyDate" should be equal to "2015-04-02T00:00:00+00:00"
And the JSON node "data.dummies.edges[1].node.dummyDate" should be equal to "2015-04-02"
And the JSON node "data.dummyGroup.foo" should be equal to "Foo #2"

@createSchema
Expand Down
2 changes: 1 addition & 1 deletion features/graphql/filters.feature
Expand Up @@ -63,7 +63,7 @@ Feature: Collections filtering
}
"""
Then the JSON node "data.dummies.edges" should have 1 element
And the JSON node "data.dummies.edges[0].node.dummyDate" should be equal to "2015-04-02T00:00:00+00:00"
And the JSON node "data.dummies.edges[0].node.dummyDate" should be equal to "2015-04-02"

@createSchema
Scenario: Retrieve a collection filtered using the search filter
Expand Down
2 changes: 1 addition & 1 deletion features/graphql/mutation.feature
Expand Up @@ -228,7 +228,7 @@ Feature: GraphQL mutation support
And the JSON node "data.updateDummy.dummy.id" should be equal to "/dummies/1"
And the JSON node "data.updateDummy.dummy.name" should be equal to "Dummy #1"
And the JSON node "data.updateDummy.dummy.description" should be equal to "Modified description."
And the JSON node "data.updateDummy.dummy.dummyDate" should be equal to "2018-06-05T00:00:00+00:00"
And the JSON node "data.updateDummy.dummy.dummyDate" should be equal to "2018-06-05"
And the JSON node "data.updateDummy.dummy.relatedDummies.edges[0].node.name" should be equal to "RelatedDummy11"
And the JSON node "data.updateDummy.clientMutationId" should be equal to "myId"

Expand Down
78 changes: 78 additions & 0 deletions features/graphql/type.feature
@@ -0,0 +1,78 @@
Feature: GraphQL type support
@createSchema
Scenario: Use a custom type for a field
Given there are 2 dummy objects with dummyDate
When I send the following GraphQL request:
"""
{
dummy(id: "/dummies/1") {
dummyDate
}
}
"""
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/json"
And the JSON node "data.dummy.dummyDate" should be equal to "2015-04-01"

Scenario: Use a custom type for an input field
When I send the following GraphQL request:
"""
mutation {
updateDummy(input: {id: "/dummies/1", dummyDate: "2019-05-24T00:00:00+00:00"}) {
dummy {
dummyDate
}
}
}
"""
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/json"
And the JSON node "data.updateDummy.dummy.dummyDate" should be equal to "2019-05-24"

Scenario: Use a custom type for a query variable
When I have the following GraphQL request:
"""
mutation UpdateDummyDate($itemId: ID!, $itemDate: DateTime!) {
updateDummy(input: {id: $itemId, dummyDate: $itemDate}) {
dummy {
dummyDate
}
}
}
"""
And I send the GraphQL request with variables:
"""
{
"itemId": "/dummies/1",
"itemDate": "2017-11-14T00:00:00+00:00"
}
"""
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/json"
And the JSON node "data.updateDummy.dummy.dummyDate" should be equal to "2017-11-14"

Scenario: Use a custom type for a query variable and use a bad value
When I have the following GraphQL request:
"""
mutation UpdateDummyDate($itemId: ID!, $itemDate: DateTime!) {
updateDummy(input: {id: $itemId, dummyDate: $itemDate}) {
dummy {
dummyDate
}
}
}
"""
And I send the GraphQL request with variables:
"""
{
"itemId": "/dummies/1",
"itemDate": "bad date"
}
"""
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/json"
And the JSON node "errors[0].message" should be equal to 'Variable "$itemDate" got invalid value "bad date"; Expected type DateTime; DateTime cannot represent non date value: "bad date"'
2 changes: 2 additions & 0 deletions phpstan.neon.dist
Expand Up @@ -76,13 +76,15 @@ parameters:
-
message: '#Binary operation "\+" between (float\|int\|)?string and 0 results in an error\.#'
path: %currentWorkingDirectory%/src/Bridge/Doctrine/Common/Filter/RangeFilterTrait.php
- '#Parameter \#1 \$objectValue of method GraphQL\\Type\\Definition\\InterfaceType::resolveType\(\) expects object, array(<string, string>)? given.#'

# Expected, due to deprecations
- '#Method ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Extension\\QueryResult(Item|Collection)ExtensionInterface::getResult\(\) invoked with 4 parameters, 1 required\.#'
- '#Method ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Extension\\QueryResult(Item|Collection)ExtensionInterface::supportsResult\(\) invoked with 3 parameters, 1-2 required\.#'
- '#Method ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Filter\\AbstractFilter::apply\(\) invoked with 5 parameters, 3-4 required\.#'
- '#Method ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Filter\\AbstractFilter::filterProperty\(\) invoked with 7 parameters, 5-6 required\.#'
- '#Method ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Filter\\FilterInterface::apply\(\) invoked with 5 parameters, 3-4 required\.#'
- '#Method ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Filter\\ExistsFilter::filterProperty\(\) invoked with 7 parameters, 5-6 required\.#'
- '#Method ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Filter\\OrderFilter::filterProperty\(\) invoked with 7 parameters, 5-6 required\.#'
- '#Method ApiPlatform\\Core\\DataProvider\\CollectionDataProviderInterface::getCollection\(\) invoked with 3 parameters, 1-2 required\.#'
- '#Method Symfony\\Component\\Serializer\\NameConverter\\NameConverterInterface::normalize\(\) invoked with 3 parameters, 1 required\.#'
Expand Down
36 changes: 32 additions & 4 deletions src/Bridge/Symfony/Bundle/Resources/config/graphql.xml
Expand Up @@ -60,24 +60,52 @@
<tag name="container.service_locator" />
</service>

<service id="api_platform.graphql.types_container" class="ApiPlatform\Core\GraphQl\Type\TypesContainer" />

<service id="api_platform.graphql.types_factory" class="ApiPlatform\Core\GraphQl\Type\TypesFactory">
<argument type="service" id="api_platform.graphql.type_locator" />
</service>

<service id="api_platform.graphql.schema_builder" class="ApiPlatform\Core\GraphQl\Type\SchemaBuilder" public="false">
<service id="api_platform.graphql.type_converter" class="ApiPlatform\Core\GraphQl\Type\TypeConverter">
<argument type="service" id="api_platform.graphql.type_builder" />
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
</service>

<service id="api_platform.graphql.type_builder" class="ApiPlatform\Core\GraphQl\Type\TypeBuilder" public="false">
<argument type="service" id="api_platform.graphql.types_container" />
<argument type="service" id="api_platform.graphql.resolver.resource_field" />
<argument type="service" id="api_platform.graphql.fields_builder_locator" />
</service>

<service id="api_platform.graphql.fields_builder" class="ApiPlatform\Core\GraphQl\Type\FieldsBuilder" public="false">
<argument type="service" id="api_platform.metadata.property.name_collection_factory" />
<argument type="service" id="api_platform.metadata.property.metadata_factory" />
<argument type="service" id="api_platform.metadata.resource.name_collection_factory" />
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
<argument type="service" id="api_platform.graphql.types_container" />
<argument type="service" id="api_platform.graphql.type_builder" />
<argument type="service" id="api_platform.graphql.type_converter" />
<argument type="service" id="api_platform.graphql.resolver.factory.item" />
<argument type="service" id="api_platform.graphql.resolver.factory.collection" />
<argument type="service" id="api_platform.graphql.resolver.factory.item_mutation" />
<argument type="service" id="api_platform.graphql.resolver.resource_field" />
<argument type="service" id="api_platform.graphql.types_factory" />
<argument type="service" id="api_platform.filter_locator" />
<argument>%api_platform.collection.pagination.enabled%</argument>
</service>

<service id="api_platform.graphql.fields_builder_locator" class="Symfony\Component\DependencyInjection\ServiceLocator" public="false">
<argument type="collection">
<argument type="service" id="api_platform.graphql.fields_builder" />
</argument>
<tag name="container.service_locator"/>
</service>

<service id="api_platform.graphql.schema_builder" class="ApiPlatform\Core\GraphQl\Type\SchemaBuilder" public="false">
<argument type="service" id="api_platform.metadata.resource.name_collection_factory" />
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
<argument type="service" id="api_platform.graphql.types_factory" />
<argument type="service" id="api_platform.graphql.types_container" />
<argument type="service" id="api_platform.graphql.fields_builder" />
</service>

<!-- Action -->

<service id="api_platform.graphql.action.entrypoint" class="ApiPlatform\Core\GraphQl\Action\EntrypointAction" public="true">
Expand Down

0 comments on commit 796f613

Please sign in to comment.