Skip to content

Commit 17bd9af

Browse files
edglevEdgaras Levinson
andauthored
fix: preserve zero fraction during response json encoding (#1223)
* fix: preserve zero fraction during response json encoding Fix zero fraction floats (1.0) being incorectly encoded as ints (1). * fix: static analysis --------- Co-authored-by: Edgaras Levinson <edgaras@eneba.com>
1 parent 8dfa6b5 commit 17bd9af

5 files changed

Lines changed: 59 additions & 21 deletions

File tree

phpstan-baseline.neon

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -430,16 +430,6 @@ parameters:
430430
count: 1
431431
path: tests/Functional/Command/ValidateCommandTest.php
432432

433-
-
434-
message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#"
435-
count: 5
436-
path: tests/Functional/Controller/GraphControllerTest.php
437-
438-
-
439-
message: "#^Parameter \\#3 \\$message of method PHPUnit\\\\Framework\\\\Assert\\:\\:assertSame\\(\\) expects string, string\\|false given\\.$#"
440-
count: 5
441-
path: tests/Functional/Controller/GraphControllerTest.php
442-
443433
-
444434
message: "#^Method Overblog\\\\GraphQLBundle\\\\Tests\\\\Functional\\\\BaseTestCase\\:\\:createKernel\\(\\) should return Symfony\\\\Component\\\\HttpKernel\\\\KernelInterface but returns object\\.$#"
445435
count: 1

src/Controller/GraphController.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ private function createResponse(Request $request, ?string $schemaName, bool $bat
6363
return new JsonResponse('', 405);
6464
}
6565
$payload = $this->processQuery($request, $schemaName, $batched);
66-
$response = new JsonResponse($payload, 200);
66+
$response = new JsonResponse('', 200);
67+
$response->setEncodingOptions(JsonResponse::DEFAULT_ENCODING_OPTIONS | JSON_PRESERVE_ZERO_FRACTION);
68+
$response->setData($payload);
6769
}
6870
$this->addCORSHeadersIfNeeded($response, $request);
6971

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
imports:
2+
- { resource: ../config.yml }
3+
- { resource: ../exception/services.yml }
4+
5+
overblog_graphql:
6+
definitions:
7+
class_namespace: "Overblog\\GraphQLBundle\\PreserveFloats\\__DEFINITIONS__"
8+
schema:
9+
query: RootQuery
10+
mutation: RootQuery
11+
mappings:
12+
types:
13+
-
14+
type: yaml
15+
dir: "%kernel.project_dir%/config/preserveFloats/mapping"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
RootQuery:
2+
type: object
3+
config:
4+
fields:
5+
float:
6+
type: Float
7+
resolve: '1.0'

tests/Functional/Controller/GraphControllerTest.php

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Overblog\GraphQLBundle\Tests\Functional\TestCase;
88
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
9+
use Symfony\Component\HttpFoundation\Response;
910
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
1011
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
1112

@@ -71,8 +72,8 @@ public function testEndpointAction(string $uri): void
7172
$this->disableCatchExceptions($client);
7273

7374
$client->request('GET', $uri, ['query' => $this->friendsQuery], [], ['CONTENT_TYPE' => 'application/graphql;charset=utf8', 'HTTP_Origin' => 'http://example.com']);
74-
$result = $client->getResponse()->getContent();
75-
$this->assertSame(['data' => $this->expectedData], json_decode($result, true), $result);
75+
$result = self::decodeResponse($client->getResponse());
76+
$this->assertSame(['data' => $this->expectedData], $result);
7677
$this->assertCORSHeadersExists($client);
7778
}
7879

@@ -108,8 +109,9 @@ public function testEndpointWithJsonContentTypeAndGetQuery(): void
108109
$client = static::createClient(['test_case' => 'connectionWithCORS']);
109110
$this->disableCatchExceptions($client);
110111
$client->request('GET', '/', ['query' => $this->friendsQuery], [], ['CONTENT_TYPE' => 'application/json']);
111-
$result = $client->getResponse()->getContent();
112-
$this->assertSame(['data' => $this->expectedData], json_decode($result, true), $result);
112+
$result = self::decodeResponse($client->getResponse());
113+
114+
$this->assertSame(['data' => $this->expectedData], $result);
113115
}
114116

115117
public function testEndpointWithInvalidBodyQuery(): void
@@ -164,6 +166,17 @@ public function testEndpointActionWithInvalidVariables(): void
164166
$client->request('GET', '/', ['query' => $query, 'variables' => '"firstFriends": 2}']);
165167
}
166168

169+
public function testEndpointActionPreservesFloats(): void
170+
{
171+
$client = static::createClient(['test_case' => 'preserveFloats']);
172+
$this->disableCatchExceptions($client);
173+
174+
$client->request('GET', '/', ['query' => 'query { float }'], [], ['CONTENT_TYPE' => 'application/graphql;charset=utf8', 'HTTP_Origin' => 'http://example.com']);
175+
$result = self::decodeResponse($client->getResponse());
176+
177+
$this->assertSame(['data' => ['float' => 1.0]], $result);
178+
}
179+
167180
public function testMultipleEndpointActionWithUnknownSchemaName(): void
168181
{
169182
$this->expectException(NotFoundHttpException::class);
@@ -188,8 +201,9 @@ public function testEndpointActionWithOperationName(): void
188201
$query = $this->friendsQuery."\n".$this->friendsTotalCountQuery;
189202

190203
$client->request('POST', '/', ['query' => $query, 'operationName' => 'FriendsQuery'], [], ['CONTENT_TYPE' => 'application/x-www-form-urlencoded']);
191-
$result = $client->getResponse()->getContent();
192-
$this->assertSame(['data' => $this->expectedData], json_decode($result, true), $result);
204+
$result = self::decodeResponse($client->getResponse());
205+
206+
$this->assertSame(['data' => $this->expectedData], $result);
193207
}
194208

195209
/**
@@ -213,13 +227,13 @@ public function testBatchEndpointAction(string $uri): void
213227

214228
$content = json_encode($data) ?: null;
215229
$client->request('POST', $uri, [], [], ['CONTENT_TYPE' => 'application/json'], $content);
216-
$result = $client->getResponse()->getContent();
230+
$result = self::decodeResponse($client->getResponse());
217231

218232
$expected = [
219233
['id' => 'friends', 'payload' => ['data' => $this->expectedData]],
220234
['id' => 'friendsTotalCount', 'payload' => ['data' => ['user' => ['friends' => ['totalCount' => 4]]]]],
221235
];
222-
$this->assertSame($expected, json_decode($result, true), $result);
236+
$this->assertSame($expected, $result);
223237
}
224238

225239
public function graphQLBatchEndpointUriProvider(): array
@@ -301,8 +315,8 @@ public function testNoCORSHeadersIfOriginHeaderNotExists(): void
301315
$client = static::createClient(['test_case' => 'connectionWithCORS']);
302316
$this->disableCatchExceptions($client);
303317
$client->request('GET', '/', ['query' => $this->friendsQuery], [], ['CONTENT_TYPE' => 'application/graphql']);
304-
$result = $client->getResponse()->getContent();
305-
$this->assertSame(['data' => $this->expectedData], json_decode($result, true), $result);
318+
$result = self::decodeResponse($client->getResponse());
319+
$this->assertSame(['data' => $this->expectedData], $result);
306320
$this->assertCORSHeadersNotExists($client);
307321
}
308322

@@ -332,4 +346,14 @@ private function assertCORSHeadersExists($client): void
332346
$this->assertSame('Content-Type, Authorization', $response->headers->get('Access-Control-Allow-Headers'));
333347
$this->assertSame('3600', $response->headers->get('Access-Control-Max-Age'));
334348
}
349+
350+
private static function decodeResponse(Response $response): array
351+
{
352+
$result = $response->getContent();
353+
self::assertIsString($result);
354+
$result = json_decode($result, true);
355+
self::assertNotNull($result);
356+
357+
return $result;
358+
}
335359
}

0 commit comments

Comments
 (0)