From 7e0948ac9e0743b854752e64aa0dbdef632f7922 Mon Sep 17 00:00:00 2001 From: Aurelien Bidon Date: Mon, 17 Jul 2023 00:47:36 +0200 Subject: [PATCH] Making sure fields are ordered the same as in the GQL query --- Sources/GraphQLKit/Graphiti+Router.swift | 14 ++- Tests/GraphQLKitTests/GraphQLKitTests.swift | 115 ++++++++++++++++++++ 2 files changed, 128 insertions(+), 1 deletion(-) diff --git a/Sources/GraphQLKit/Graphiti+Router.swift b/Sources/GraphQLKit/Graphiti+Router.swift index 46dbb33..b6a4007 100644 --- a/Sources/GraphQLKit/Graphiti+Router.swift +++ b/Sources/GraphQLKit/Graphiti+Router.swift @@ -23,4 +23,16 @@ enum GraphQLResolveError: Swift.Error { case noQueryFound } -extension GraphQLResult: Content { } +extension GraphQLResult: Content { + public func encodeResponse(for request: Request) -> EventLoopFuture { + return request.eventLoop.submit { + Response( + status: .ok, + headers: [ + "Content-Type": "application/json" + ], + body: .init(data: try GraphQLJSONEncoder().encode(self)) + ) + } + } +} diff --git a/Tests/GraphQLKitTests/GraphQLKitTests.swift b/Tests/GraphQLKitTests/GraphQLKitTests.swift index c97d5e5..99d6e8e 100644 --- a/Tests/GraphQLKitTests/GraphQLKitTests.swift +++ b/Tests/GraphQLKitTests/GraphQLKitTests.swift @@ -28,6 +28,22 @@ final class GraphQLKitTests: XCTestCase { } } + struct Address: Content { + public var number: Int + public var streetName: String + public var additionalStreetName: String? + public var city: String + public var postalCode: String + public var country: String + } + + struct Person: Content { + public var firstName: String + public var lastName: String + public var age: UInt + public var address: Address + } + struct ProtectedResolver { func test(store: Request, _: NoArguments) throws -> String { _ = try store.auth.require(SomeBearerAuthenticator.User.self) @@ -48,6 +64,16 @@ final class GraphQLKitTests: XCTestCase { func number(store: Request, _: NoArguments) -> Int { 42 } + + func person(store: Request, _: NoArguments) throws -> Person { + return Person(firstName: "John", lastName: "Appleseed", age: 42, address: Address( + number: 767, + streetName: "Fifth Avenue", + city: "New York", + postalCode: "NY 10153", + country: "United States" + )) + } } let protectedSchema = try! Schema { @@ -58,9 +84,28 @@ final class GraphQLKitTests: XCTestCase { } let schema = try! Schema { + Scalar(UInt.self) + + Type(Address.self) { + Field("additionalStreetName", at: \Address.additionalStreetName) + Field("city", at: \Address.city) + Field("country", at: \Address.country) + Field("number", at: \Address.number) + Field("postalCode", at: \Address.postalCode) + Field("streetName", at: \Address.streetName) + } + + Type(Person.self) { + Field("address", at: \Person.address) + Field("age", at: \Person.age) + Field("firstName", at: \Person.firstName) + Field("lastName", at: \Person.lastName) + } + Query { Field("test", at: Resolver.test) Field("number", at: Resolver.number) + Field("person", at: Resolver.person) } } @@ -231,4 +276,74 @@ final class GraphQLKitTests: XCTestCase { XCTAssertEqual(res.body.readString(length: expected.count), expected) } } + + func testFieldsOrder() throws { + let query1Request = QueryRequest(query: // this query returns fields in arbitrary order + """ + query { + person { + firstName + lastName + age + address { + number + streetName + city + postalCode + country + } + } + } + """, operationName: nil, variables: nil) + let query2Request = QueryRequest(query: // this query will return all fields in alphabetical order + """ + query { + person { + address { + city + country + number + postalCode + streetName + } + age + firstName + lastName + } + } + """, operationName: nil, variables: nil) + let data1 = String(data: try! JSONEncoder().encode(query1Request), encoding: .utf8)! + let data2 = String(data: try! JSONEncoder().encode(query2Request), encoding: .utf8)! + + let app = Application(.testing) + defer { app.shutdown() } + + app.register(graphQLSchema: schema, withResolver: Resolver()) + + var body1 = ByteBufferAllocator().buffer(capacity: 0) + body1.writeString(data1) + var headers1 = HTTPHeaders() + headers1.replaceOrAdd(name: .contentLength, value: body1.readableBytes.description) + headers1.contentType = .json + + var body2 = ByteBufferAllocator().buffer(capacity: 0) + body2.writeString(data2) + var headers2 = HTTPHeaders() + headers2.replaceOrAdd(name: .contentLength, value: body2.readableBytes.description) + headers2.contentType = .json + + try app.testable().test(.POST, "/graphql", headers: headers1, body: body1) { res in + XCTAssertEqual(res.status, .ok) + var res = res + let expected = #"{"data":{"person":{"firstName":"John","lastName":"Appleseed","age":42,"address":{"number":767,"streetName":"Fifth Avenue","city":"New York","postalCode":"NY 10153","country":"United States"}}}}"# + XCTAssertEqual(res.body.readString(length: expected.count), expected) + } + + try app.testable().test(.POST, "/graphql", headers: headers2, body: body2) { res in + XCTAssertEqual(res.status, .ok) + var res = res + let expected = #"{"data":{"person":{"address":{"city":"New York","country":"United States","number":767,"postalCode":"NY 10153","streetName":"Fifth Avenue"},"age":42,"firstName":"John","lastName":"Appleseed"}}}"# + XCTAssertEqual(res.body.readString(length: expected.count), expected) + } + } }