Skip to content

Commit

Permalink
change operation to OperationName in the parser (#3568)
Browse files Browse the repository at this point in the history
  • Loading branch information
Julien Lenne authored May 18, 2020
1 parent cfc05d1 commit d83d502
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 32 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* GraphQL: Add page-based pagination (#3175, #3517)
* GraphQL: Possibility to add a custom description for queries, mutations and subscriptions (#3477, #3514)
* GraphQL: Support for field name conversion (serialized name) (#3455, #3516)
* GraphQL: **BC** `operation` is now `operationName` to follow the standard (#3568)
* OpenAPI: Add PHP default values to the documentation (#2386)
* Deprecate using a validation groups generator service not implementing `ApiPlatform\Core\Bridge\Symfony\Validator\ValidationGroupsGeneratorInterface` (#3346)

Expand All @@ -34,7 +35,6 @@
* HTTP: Location header is only set on POST with a 201 or between 300 and 400 #3497
* GraphQL: Do not allow empty cursor values on `before` or `after` #3360
* Bump versions of Swagger UI, GraphiQL and GraphQL Playground #3510
>>>>>>> 2.5

## 2.5.4

Expand Down
6 changes: 3 additions & 3 deletions features/bootstrap/GraphqlContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,11 @@ public function ISendTheGraphqlRequestWithVariables(PyStringNode $variables)
}

/**
* @When I send the GraphQL request with operation :operation
* @When I send the GraphQL request with operationName :operationName
*/
public function ISendTheGraphqlRequestWithOperation(string $operation)
public function ISendTheGraphqlRequestWithOperation(string $operationName)
{
$this->graphqlRequest['operation'] = $operation;
$this->graphqlRequest['operationName'] = $operationName;
$this->sendGraphqlRequest();
}

Expand Down
4 changes: 2 additions & 2 deletions features/graphql/query.feature
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,13 @@ Feature: GraphQL query support
}
}
"""
And I send the GraphQL request with operation "DummyWithId2"
And I send the GraphQL request with operationName "DummyWithId2"
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.dummyItem.id" should be equal to "/dummies/2"
And the JSON node "data.dummyItem.name" should be equal to "Dummy #2"
And I send the GraphQL request with operation "DummyWithId1"
And I send the GraphQL request with operationName "DummyWithId1"
And the JSON node "data.dummyItem.name" should be equal to "Dummy #1"

Scenario: Use serialization groups
Expand Down
29 changes: 14 additions & 15 deletions src/GraphQl/Action/EntrypointAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,13 @@ public function __invoke(Request $request): Response
}
}

[$query, $operation, $variables] = $this->parseRequest($request);
[$query, $operationName, $variables] = $this->parseRequest($request);
if (null === $query) {
throw new BadRequestHttpException('GraphQL query is not valid.');
}

$executionResult = $this->executor
->executeQuery($this->schemaBuilder->getSchema(), $query, null, null, $variables, $operation)
->executeQuery($this->schemaBuilder->getSchema(), $query, null, null, $variables, $operationName)
->setErrorFormatter([$this->normalizer, 'normalize']);
} catch (\Exception $exception) {
$executionResult = (new ExecutionResult(null, [new Error($exception->getMessage(), null, null, null, null, $exception)]))
Expand All @@ -91,34 +91,34 @@ public function __invoke(Request $request): Response
private function parseRequest(Request $request): array
{
$query = $request->query->get('query');
$operation = $request->query->get('operation');
$operationName = $request->query->get('operationName');
if ($variables = $request->query->get('variables', [])) {
$variables = $this->decodeVariables($variables);
}

if (!$request->isMethod('POST')) {
return [$query, $operation, $variables];
return [$query, $operationName, $variables];
}

if ('json' === $request->getContentType()) {
return $this->parseData($query, $operation, $variables, $request->getContent());
return $this->parseData($query, $operationName, $variables, $request->getContent());
}

if ('graphql' === $request->getContentType()) {
$query = $request->getContent();
}

if ('multipart' === $request->getContentType()) {
return $this->parseMultipartRequest($query, $operation, $variables, $request->request->all(), $request->files->all());
return $this->parseMultipartRequest($query, $operationName, $variables, $request->request->all(), $request->files->all());
}

return [$query, $operation, $variables];
return [$query, $operationName, $variables];
}

/**
* @throws BadRequestHttpException
*/
private function parseData(?string $query, ?string $operation, array $variables, string $jsonContent): array
private function parseData(?string $query, ?string $operationName, array $variables, string $jsonContent): array
{
if (!\is_array($data = json_decode($jsonContent, true))) {
throw new BadRequestHttpException('GraphQL data is not valid JSON.');
Expand All @@ -132,24 +132,23 @@ private function parseData(?string $query, ?string $operation, array $variables,
$variables = \is_array($data['variables']) ? $data['variables'] : $this->decodeVariables($data['variables']);
}

if (isset($data['operation'])) {
$operation = $data['operation'];
if (isset($data['operationName'])) {
$operationName = $data['operationName'];
}

return [$query, $operation, $variables];
return [$query, $operationName, $variables];
}

/**
* @throws BadRequestHttpException
*/
private function parseMultipartRequest(?string $query, ?string $operation, array $variables, array $bodyParameters, array $files): array
private function parseMultipartRequest(?string $query, ?string $operationName, array $variables, array $bodyParameters, array $files): array
{
if ((null === $operations = $bodyParameters['operations'] ?? null) || (null === $map = $bodyParameters['map'] ?? null)) {
throw new BadRequestHttpException('GraphQL multipart request does not respect the specification.');
}

/** @var string $operations */
[$query, $operation, $variables] = $this->parseData($query, $operation, $variables, $operations);
[$query, $operationName, $variables] = $this->parseData($query, $operationName, $variables, $operations);

/** @var string $map */
if (!\is_array($decodedMap = json_decode($map, true))) {
Expand All @@ -158,7 +157,7 @@ private function parseMultipartRequest(?string $query, ?string $operation, array

$variables = $this->applyMapToVariables($decodedMap, $variables, $files);

return [$query, $operation, $variables];
return [$query, $operationName, $variables];
}

/**
Expand Down
22 changes: 11 additions & 11 deletions tests/GraphQl/Action/EntrypointActionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public function testGetHtmlAction(): void

public function testGetAction(): void
{
$request = new Request(['query' => 'graphqlQuery', 'variables' => '["graphqlVariable"]', 'operation' => 'graphqlOperationName']);
$request = new Request(['query' => 'graphqlQuery', 'variables' => '["graphqlVariable"]', 'operationName' => 'graphqlOperationName']);
$request->setRequestFormat('json');
$mockedEntrypoint = $this->getEntrypointAction();

Expand All @@ -67,7 +67,7 @@ public function testGetAction(): void

public function testPostRawAction(): void
{
$request = new Request(['variables' => '["graphqlVariable"]', 'operation' => 'graphqlOperationName'], [], [], [], [], [], 'graphqlQuery');
$request = new Request(['variables' => '["graphqlVariable"]', 'operationName' => 'graphqlOperationName'], [], [], [], [], [], 'graphqlQuery');
$request->setFormat('graphql', 'application/graphql');
$request->setMethod('POST');
$request->headers->set('Content-Type', 'application/graphql');
Expand All @@ -78,7 +78,7 @@ public function testPostRawAction(): void

public function testPostJsonAction(): void
{
$request = new Request([], [], [], [], [], [], '{"query": "graphqlQuery", "variables": "[\"graphqlVariable\"]", "operation": "graphqlOperationName"}');
$request = new Request([], [], [], [], [], [], '{"query": "graphqlQuery", "variables": "[\"graphqlVariable\"]", "operationName": "graphqlOperationName"}');
$request->setMethod('POST');
$request->headers->set('Content-Type', 'application/json');
$mockedEntrypoint = $this->getEntrypointAction();
Expand Down Expand Up @@ -119,14 +119,14 @@ public function multipartRequestProvider(): array

return [
'upload a single file' => [
'{"query": "graphqlQuery", "variables": {"file": null}, "operation": "graphqlOperationName"}',
'{"query": "graphqlQuery", "variables": {"file": null}, "operationName": "graphqlOperationName"}',
'{"file": ["variables.file"]}',
['file' => $file],
['file' => $file],
new JsonResponse(['GraphQL']),
],
'upload multiple files' => [
'{"query": "graphqlQuery", "variables": {"files": [null, null, null]}, "operation": "graphqlOperationName"}',
'{"query": "graphqlQuery", "variables": {"files": [null, null, null]}, "operationName": "graphqlOperationName"}',
'{"0": ["variables.files.0"], "1": ["variables.files.1"], "2": ["variables.files.2"]}',
[
'0' => $file,
Expand All @@ -150,7 +150,7 @@ public function multipartRequestProvider(): array
new Response('{"errors":[{"message":"GraphQL multipart request does not respect the specification.","extensions":{"category":"user","status":400}}]}'),
],
'upload without providing map' => [
'{"query": "graphqlQuery", "variables": {"file": null}, "operation": "graphqlOperationName"}',
'{"query": "graphqlQuery", "variables": {"file": null}, "operationName": "graphqlOperationName"}',
null,
['file' => $file],
['file' => null],
Expand All @@ -164,28 +164,28 @@ public function multipartRequestProvider(): array
new Response('{"errors":[{"message":"GraphQL data is not valid JSON.","extensions":{"category":"user","status":400}}]}'),
],
'upload with invalid map JSON' => [
'{"query": "graphqlQuery", "variables": {"file": null}, "operation": "graphqlOperationName"}',
'{"query": "graphqlQuery", "variables": {"file": null}, "operationName": "graphqlOperationName"}',
'{invalid}',
['file' => $file],
['file' => null],
new Response('{"errors":[{"message":"GraphQL multipart request map is not valid JSON.","extensions":{"category":"user","status":400}}]}'),
],
'upload with no file' => [
'{"query": "graphqlQuery", "variables": {"file": null}, "operation": "graphqlOperationName"}',
'{"query": "graphqlQuery", "variables": {"file": null}, "operationName": "graphqlOperationName"}',
'{"file": ["file"]}',
[],
['file' => null],
new Response('{"errors":[{"message":"GraphQL multipart request file has not been sent correctly.","extensions":{"category":"user","status":400}}]}'),
],
'upload with wrong map' => [
'{"query": "graphqlQuery", "variables": {"file": null}, "operation": "graphqlOperationName"}',
'{"query": "graphqlQuery", "variables": {"file": null}, "operationName": "graphqlOperationName"}',
'{"file": ["file"]}',
['file' => $file],
['file' => null],
new Response('{"errors":[{"message":"GraphQL multipart request path in map is invalid.","extensions":{"category":"user","status":400}}]}'),
],
'upload when variable path does not exist' => [
'{"query": "graphqlQuery", "variables": {"file": null}, "operation": "graphqlOperationName"}',
'{"query": "graphqlQuery", "variables": {"file": null}, "operationName": "graphqlOperationName"}',
'{"file": ["variables.wrong"]}',
['file' => $file],
['file' => null],
Expand Down Expand Up @@ -217,7 +217,7 @@ public function testBadMethodAction(): void

public function testBadVariablesAction(): void
{
$request = new Request(['query' => 'graphqlQuery', 'variables' => 'graphqlVariable', 'operation' => 'graphqlOperationName']);
$request = new Request(['query' => 'graphqlQuery', 'variables' => 'graphqlVariable', 'operationName' => 'graphqlOperationName']);
$request->setRequestFormat('json');
$mockedEntrypoint = $this->getEntrypointAction();

Expand Down

0 comments on commit d83d502

Please sign in to comment.