From 42d81033877dc104eefe1f14cfbac2e3d3049087 Mon Sep 17 00:00:00 2001 From: Jay Herron Date: Sun, 5 Apr 2026 02:22:02 -0600 Subject: [PATCH 1/2] chore: Add swift-format file --- .swift-format | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .swift-format diff --git a/.swift-format b/.swift-format new file mode 100644 index 0000000..1ffdbf5 --- /dev/null +++ b/.swift-format @@ -0,0 +1,7 @@ +{ + "version": 1, + "indentation" : { + "spaces" : 4 + }, + "lineBreakBeforeEachArgument": true +} From 10e51950e2d305b7e911f321c11c67dedae19199 Mon Sep 17 00:00:00 2001 From: Jay Herron Date: Sun, 5 Apr 2026 02:24:35 -0600 Subject: [PATCH 2/2] refactor: Applies formatter --- Examples/HelloWorld/Package.swift | 4 +- .../Sources/HelloWorld/HelloWorld.swift | 9 +- Package.swift | 4 +- .../GraphQLJSONEncoder+ContentEncoder.swift | 21 ++- .../Content/HTTPMediaType+jsonGraphQL.swift | 8 +- Sources/GraphQLVapor/GraphQLConfig.swift | 5 +- Sources/GraphQLVapor/GraphQLHandler.swift | 3 +- .../HTTP/GraphQLHandler+HTTP.swift | 5 +- .../GraphQLVapor/IDEs/GraphiQLHandler.swift | 152 +++++++++--------- .../GraphQLVapor/RoutesBuilder+graphql.swift | 25 ++- .../GraphQLHandler+handleWebSocket.swift | 26 ++- .../HTTPStatusCodeGraphQLJSONTests.swift | 43 +++-- .../HTTPStatusCodeJSONTests.swift | 43 +++-- Tests/GraphQLVaporTests/HTTPTests.swift | 33 ++-- Tests/GraphQLVaporTests/Utilities.swift | 2 +- Tests/GraphQLVaporTests/WebSocketTests.swift | 132 ++++++++++----- 16 files changed, 318 insertions(+), 197 deletions(-) diff --git a/Examples/HelloWorld/Package.swift b/Examples/HelloWorld/Package.swift index 6914ffe..e90570c 100644 --- a/Examples/HelloWorld/Package.swift +++ b/Examples/HelloWorld/Package.swift @@ -5,7 +5,7 @@ import PackageDescription let package = Package( name: "HelloWorld", platforms: [ - .macOS(.v13), + .macOS(.v13) ], dependencies: [ .package(name: "graphql-vapor", path: "../../"), @@ -22,6 +22,6 @@ let package = Package( .product(name: "GraphQL", package: "GraphQL"), .product(name: "Vapor", package: "vapor"), ] - ), + ) ] ) diff --git a/Examples/HelloWorld/Sources/HelloWorld/HelloWorld.swift b/Examples/HelloWorld/Sources/HelloWorld/HelloWorld.swift index 7c62cf9..ce11ae6 100644 --- a/Examples/HelloWorld/Sources/HelloWorld/HelloWorld.swift +++ b/Examples/HelloWorld/Sources/HelloWorld/HelloWorld.swift @@ -19,7 +19,7 @@ struct HelloWorld { resolve: { _, _, _, _ in "World" } - ), + ) ] ), subscription: GraphQLObjectType( @@ -34,11 +34,14 @@ struct HelloWorld { subscribe: { _, _, _, _ in let clock = ContinuousClock() let start = clock.now - return AsyncTimerSequence(interval: .seconds(3), clock: ContinuousClock()).map { instant in + return AsyncTimerSequence( + interval: .seconds(3), + clock: ContinuousClock() + ).map { instant in "World at \(start.duration(to: instant))" } } - ), + ) ] ) ) diff --git a/Package.swift b/Package.swift index aec5449..9bfa0c4 100644 --- a/Package.swift +++ b/Package.swift @@ -5,13 +5,13 @@ import PackageDescription let package = Package( name: "GraphQLVapor", platforms: [ - .macOS(.v13), + .macOS(.v13) ], products: [ .library( name: "GraphQLVapor", targets: ["GraphQLVapor"] - ), + ) ], dependencies: [ .package(url: "https://github.com/GraphQLSwift/GraphQL.git", from: "4.0.0"), diff --git a/Sources/GraphQLVapor/Content/GraphQLJSONEncoder+ContentEncoder.swift b/Sources/GraphQLVapor/Content/GraphQLJSONEncoder+ContentEncoder.swift index c37a941..6f9fe0e 100644 --- a/Sources/GraphQLVapor/Content/GraphQLJSONEncoder+ContentEncoder.swift +++ b/Sources/GraphQLVapor/Content/GraphQLJSONEncoder+ContentEncoder.swift @@ -2,21 +2,30 @@ import GraphQL import Vapor extension GraphQLJSONEncoder: @retroactive ContentEncoder { - public func encode(_ encodable: E, to body: inout NIOCore.ByteBuffer, headers: inout NIOHTTP1.HTTPHeaders) throws { + public func encode( + _ encodable: E, + to body: inout NIOCore.ByteBuffer, + headers: inout NIOHTTP1.HTTPHeaders + ) throws { try encode(encodable, to: &body, headers: &headers, userInfo: [:]) } - public func encode(_ encodable: E, to body: inout ByteBuffer, headers: inout HTTPHeaders, userInfo: [CodingUserInfoKey: Sendable]) throws { + public func encode( + _ encodable: E, + to body: inout ByteBuffer, + headers: inout HTTPHeaders, + userInfo: [CodingUserInfoKey: Sendable] + ) throws { headers.contentType = .jsonGraphQL - if !userInfo.isEmpty { // Changing a coder's userInfo is a thread-unsafe mutation, operate on a copy + if !userInfo.isEmpty { // Changing a coder's userInfo is a thread-unsafe mutation, operate on a copy let encoder = GraphQLJSONEncoder.custom( dates: dateEncodingStrategy, data: dataEncodingStrategy, keys: keyEncodingStrategy, format: outputFormatting, floats: nonConformingFloatEncodingStrategy - ) // don't use userInfo parameter of `JSONEncoder.custom()` until Swift 6.2 is required + ) // don't use userInfo parameter of `JSONEncoder.custom()` until Swift 6.2 is required encoder.userInfo = self.userInfo.merging(userInfo) { $1 } try body.writeBytes(encoder.encode(encodable)) } else { @@ -25,7 +34,7 @@ extension GraphQLJSONEncoder: @retroactive ContentEncoder { } } -public extension GraphQLJSONEncoder { +extension GraphQLJSONEncoder { /// Convenience for creating a customized ``Foundation/GraphQLJSONEncoder``. /// /// let encoder: GraphQLJSONEncoder = .custom(dates: .millisecondsSince1970) @@ -38,7 +47,7 @@ public extension GraphQLJSONEncoder { /// - floats: Non-conforming float encoding strategy. /// - userInfo: Coder userInfo. /// - Returns: Newly created ``Foundation/JSONEncoder``. - static func custom( + public static func custom( dates dateStrategy: GraphQLJSONEncoder.DateEncodingStrategy? = nil, data dataStrategy: GraphQLJSONEncoder.DataEncodingStrategy? = nil, keys keyStrategy: GraphQLJSONEncoder.KeyEncodingStrategy? = nil, diff --git a/Sources/GraphQLVapor/Content/HTTPMediaType+jsonGraphQL.swift b/Sources/GraphQLVapor/Content/HTTPMediaType+jsonGraphQL.swift index c589669..89b4a8c 100644 --- a/Sources/GraphQLVapor/Content/HTTPMediaType+jsonGraphQL.swift +++ b/Sources/GraphQLVapor/Content/HTTPMediaType+jsonGraphQL.swift @@ -1,5 +1,9 @@ import Vapor -public extension HTTPMediaType { - static let jsonGraphQL = HTTPMediaType(type: "application", subType: "graphql-response+json", parameters: ["charset": "utf-8"]) +extension HTTPMediaType { + public static let jsonGraphQL = HTTPMediaType( + type: "application", + subType: "graphql-response+json", + parameters: ["charset": "utf-8"] + ) } diff --git a/Sources/GraphQLVapor/GraphQLConfig.swift b/Sources/GraphQLVapor/GraphQLConfig.swift index 92049f7..752e26c 100644 --- a/Sources/GraphQLVapor/GraphQLConfig.swift +++ b/Sources/GraphQLVapor/GraphQLConfig.swift @@ -85,7 +85,10 @@ public struct GraphQLConfig< /// authorization using the `payload` field of the `connection_init` message. /// Throw from this closure to indicate that authorization has failed. public init( - onWebSocketInit: @Sendable @escaping (WebSocketInit, Request) async throws -> WebSocketInitResult = { (_: EmptyWebSocketInit, _: Request) in } + onWebSocketInit: + @Sendable @escaping (WebSocketInit, Request) async throws -> WebSocketInitResult = { + (_: EmptyWebSocketInit, _: Request) in + } ) { self.onWebSocketInit = onWebSocketInit } diff --git a/Sources/GraphQLVapor/GraphQLHandler.swift b/Sources/GraphQLVapor/GraphQLHandler.swift index 917a881..53c0342 100644 --- a/Sources/GraphQLVapor/GraphQLHandler.swift +++ b/Sources/GraphQLVapor/GraphQLHandler.swift @@ -9,5 +9,6 @@ struct GraphQLHandler< let schema: GraphQLSchema let rootValue: any Sendable let config: GraphQLConfig - let computeContext: @Sendable (GraphQLContextComputationInputs) async throws -> Context + let computeContext: + @Sendable (GraphQLContextComputationInputs) async throws -> Context } diff --git a/Sources/GraphQLVapor/HTTP/GraphQLHandler+HTTP.swift b/Sources/GraphQLVapor/HTTP/GraphQLHandler+HTTP.swift index 0dc758a..3f8c0d0 100644 --- a/Sources/GraphQLVapor/HTTP/GraphQLHandler+HTTP.swift +++ b/Sources/GraphQLVapor/HTTP/GraphQLHandler+HTTP.swift @@ -73,7 +73,10 @@ extension GraphQLHandler { // This indicates a request parsing error return GraphQLResult(data: nil, errors: [error]) } catch { - return GraphQLResult(data: nil, errors: [GraphQLError(message: error.localizedDescription)]) + return GraphQLResult( + data: nil, + errors: [GraphQLError(message: error.localizedDescription)] + ) } return result } diff --git a/Sources/GraphQLVapor/IDEs/GraphiQLHandler.swift b/Sources/GraphQLVapor/IDEs/GraphiQLHandler.swift index 8b62301..27b078a 100644 --- a/Sources/GraphQLVapor/IDEs/GraphiQLHandler.swift +++ b/Sources/GraphQLVapor/IDEs/GraphiQLHandler.swift @@ -14,89 +14,89 @@ enum GraphiQLHandler { graphiQLFetcherArgs += ", subscriptionUrl: '\(subscriptionUrl)'" } return """ - - - - - - GraphiQL 5 with React 19 and GraphiQL Explorer - - - - - - + - - -
-
Loading…
-
- - - """ + const container = document.getElementById('graphiql'); + const root = ReactDOM.createRoot(container); + root.render(React.createElement(App)); + + + +
+
Loading…
+
+ + + """ } } diff --git a/Sources/GraphQLVapor/RoutesBuilder+graphql.swift b/Sources/GraphQLVapor/RoutesBuilder+graphql.swift index c71e969..32aac95 100644 --- a/Sources/GraphQLVapor/RoutesBuilder+graphql.swift +++ b/Sources/GraphQLVapor/RoutesBuilder+graphql.swift @@ -1,7 +1,7 @@ import GraphQL import Vapor -public extension RoutesBuilder { +extension RoutesBuilder { /// Registers graphql routes that respond using the provided schema. /// /// The resulting routes adhere to the [GraphQL over HTTP spec](https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md). @@ -18,7 +18,7 @@ public extension RoutesBuilder { /// - rootValue: The `rootValue` GraphQL execution arg. This is the object passed to the root resolvers. /// - config: GraphQL Handler configuration options. See type documentation for details. /// - computeContext: A closure used to compute the GraphQL context from incoming requests. This must be provided. - func graphql< + public func graphql< Context: Sendable, WebSocketInit: Equatable & Codable & Sendable, WebSocketInitResult: Sendable @@ -26,18 +26,26 @@ public extension RoutesBuilder { _ path: [PathComponent] = ["graphql"], schema: GraphQLSchema, rootValue: any Sendable = (), - config: GraphQLConfig = GraphQLConfig(), - computeContext: @Sendable @escaping (GraphQLContextComputationInputs) async throws -> Context + config: GraphQLConfig = GraphQLConfig< + EmptyWebSocketInit, Void + >(), + computeContext: + @Sendable @escaping (GraphQLContextComputationInputs) async throws + -> Context ) { ContentConfiguration.global.use(encoder: GraphQLJSONEncoder(), for: .jsonGraphQL) ContentConfiguration.global.use(decoder: JSONDecoder(), for: .jsonGraphQL) // https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md#request - let handler = GraphQLHandler(schema: schema, rootValue: rootValue, config: config, computeContext: computeContext) + let handler = GraphQLHandler( + schema: schema, + rootValue: rootValue, + config: config, + computeContext: computeContext + ) get(path) { request in // WebSocket handling - if - config.subscriptionProtocols.contains(.websocket), + if config.subscriptionProtocols.contains(.websocket), request.headers.connection?.value.lowercased() == "upgrade" { return try await handler.handleWebSocket(request: request) @@ -49,7 +57,8 @@ public extension RoutesBuilder { case .graphiql: return try await GraphiQLHandler.respond( url: request.url.string, - subscriptionUrl: config.subscriptionProtocols.contains(.websocket) ? request.url.string : nil + subscriptionUrl: config.subscriptionProtocols.contains(.websocket) + ? request.url.string : nil ) case .none: // Let this get caught by the graphQLRequest decoding diff --git a/Sources/GraphQLVapor/WebSocket/GraphQLHandler+handleWebSocket.swift b/Sources/GraphQLVapor/WebSocket/GraphQLHandler+handleWebSocket.swift index ce0cc7b..f0836cc 100644 --- a/Sources/GraphQLVapor/WebSocket/GraphQLHandler+handleWebSocket.swift +++ b/Sources/GraphQLVapor/WebSocket/GraphQLHandler+handleWebSocket.swift @@ -1,8 +1,9 @@ import GraphQL +import Vapor + import struct GraphQLTransportWS.EmptyInitPayload import class GraphQLTransportWS.Server import class GraphQLWS.Server -import Vapor extension GraphQLHandler { func handleWebSocket( @@ -11,7 +12,10 @@ extension GraphQLHandler { let subProtocol = try negotiateSubProtocol(request: request) let response = Response(status: .switchingProtocols) response.upgrader = WebSocketUpgrader( - maxFrameSize: .init(integerLiteral: (config.maxBodySize ?? request.application.routes.defaultMaxBodySize).value), + maxFrameSize: .init( + integerLiteral: (config.maxBodySize ?? request.application.routes.defaultMaxBodySize) + .value + ), shouldUpgrade: { request.eventLoop.makeFutureWithTask { ["Sec-WebSocket-Protocol": subProtocol.rawValue] @@ -26,7 +30,7 @@ extension GraphQLHandler { switch result { case .success: continuation.finish() - case let .failure(error): + case .failure(let error): continuation.finish(throwing: error) } } @@ -36,7 +40,10 @@ extension GraphQLHandler { switch subProtocol { case .graphqlTransportWs: // https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md - let server = GraphQLTransportWS.Server>( + let server = GraphQLTransportWS.Server< + WebSocketInit, WebSocketInitResult, + AsyncThrowingStream + >( messenger: messenger, onInit: { initPayload in try await config.websocket.onWebSocketInit(initPayload, request) @@ -80,7 +87,10 @@ extension GraphQLHandler { } case .graphqlWs: // https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md - let server = GraphQLWS.Server>( + let server = GraphQLWS.Server< + WebSocketInit, WebSocketInitResult, + AsyncThrowingStream + >( messenger: messenger, onInit: { initPayload in try await config.websocket.onWebSocketInit(initPayload, request) @@ -145,7 +155,11 @@ extension GraphQLHandler { } guard let subProtocol = subProtocol else { // If they provided options but none matched, fail - throw Abort(.badRequest, reason: "Unable to negotiate subprotocol. \(WebSocketSubProtocol.allCases) are supported.") + throw Abort( + .badRequest, + reason: + "Unable to negotiate subprotocol. \(WebSocketSubProtocol.allCases) are supported." + ) } return subProtocol } diff --git a/Tests/GraphQLVaporTests/HTTPStatusCodeGraphQLJSONTests.swift b/Tests/GraphQLVaporTests/HTTPStatusCodeGraphQLJSONTests.swift index 024f959..f8f8873 100644 --- a/Tests/GraphQLVaporTests/HTTPStatusCodeGraphQLJSONTests.swift +++ b/Tests/GraphQLVaporTests/HTTPStatusCodeGraphQLJSONTests.swift @@ -1,13 +1,14 @@ import Foundation import GraphQL import GraphQLTransportWS -@testable import GraphQLVapor import GraphQLWS import NIOFoundationCompat import Testing import Vapor import VaporTesting +@testable import GraphQLVapor + /// Validates status code behavior for the `application/graphql-response+json` media type. /// /// https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md#applicationgraphql-responsejson @@ -51,9 +52,11 @@ struct HTTPStatusCodeGraphQLJSONTests { } try await app.test(.POST, "/graphql", headers: jsonGraphQLHeaders) { req in - try req.content.encode(GraphQLRequest( - query: "{" - )) + try req.content.encode( + GraphQLRequest( + query: "{" + ) + ) } afterResponse: { response in #expect(response.status == .badRequest) } @@ -69,9 +72,11 @@ struct HTTPStatusCodeGraphQLJSONTests { try await app.test(.POST, "/graphql", headers: jsonGraphQLHeaders) { req in // Fails "No Unused Variables" validation rule - try req.content.encode(GraphQLRequest( - query: "query A($name: String) { hello }" - )) + try req.content.encode( + GraphQLRequest( + query: "query A($name: String) { hello }" + ) + ) } afterResponse: { response in #expect(response.status == .badRequest) } @@ -86,9 +91,11 @@ struct HTTPStatusCodeGraphQLJSONTests { } try await app.test(.POST, "/graphql", headers: jsonGraphQLHeaders) { req in - try req.content.encode(GraphQLRequest( - query: "abc { hello }" - )) + try req.content.encode( + GraphQLRequest( + query: "abc { hello }" + ) + ) } afterResponse: { response in #expect(response.status == .badRequest) } @@ -105,7 +112,7 @@ struct HTTPStatusCodeGraphQLJSONTests { "get": GraphQLField( type: GraphQLString, args: [ - "name": GraphQLArgument(type: GraphQLString), + "name": GraphQLArgument(type: GraphQLString) ], resolve: { _, args, _, _ in guard let name = args["name"].string else { @@ -113,7 +120,7 @@ struct HTTPStatusCodeGraphQLJSONTests { } return name } - ), + ) ] ) ) @@ -122,10 +129,12 @@ struct HTTPStatusCodeGraphQLJSONTests { } try await app.test(.POST, "/graphql", headers: jsonGraphQLHeaders) { req in - try req.content.encode(GraphQLRequest( - query: "query getName($name: String!) { get(name: $name) }", - variables: ["name": .null] - )) + try req.content.encode( + GraphQLRequest( + query: "query getName($name: String!) { get(name: $name) }", + variables: ["name": .null] + ) + ) } afterResponse: { response in #expect(response.status == .badRequest) } @@ -144,7 +153,7 @@ struct HTTPStatusCodeGraphQLJSONTests { resolve: { _, _, _, _ in throw GraphQLError(message: "Something went wrong") } - ), + ) ] ) ) diff --git a/Tests/GraphQLVaporTests/HTTPStatusCodeJSONTests.swift b/Tests/GraphQLVaporTests/HTTPStatusCodeJSONTests.swift index 7147d0f..3932f4f 100644 --- a/Tests/GraphQLVaporTests/HTTPStatusCodeJSONTests.swift +++ b/Tests/GraphQLVaporTests/HTTPStatusCodeJSONTests.swift @@ -1,13 +1,14 @@ import Foundation import GraphQL import GraphQLTransportWS -@testable import GraphQLVapor import GraphQLWS import NIOFoundationCompat import Testing import Vapor import VaporTesting +@testable import GraphQLVapor + /// Validates status code behavior for the `application/json` media type. /// /// https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md#applicationjson @@ -51,9 +52,11 @@ struct HTTPStatusCodeJSONTests { } try await app.test(.POST, "/graphql", headers: jsonHeaders) { req in - try req.content.encode(GraphQLRequest( - query: "{" - )) + try req.content.encode( + GraphQLRequest( + query: "{" + ) + ) } afterResponse: { response in #expect(response.status == .ok) } @@ -69,9 +72,11 @@ struct HTTPStatusCodeJSONTests { try await app.test(.POST, "/graphql", headers: jsonHeaders) { req in // Fails "No Unused Variables" validation rule - try req.content.encode(GraphQLRequest( - query: "query A($name: String) { hello }" - )) + try req.content.encode( + GraphQLRequest( + query: "query A($name: String) { hello }" + ) + ) } afterResponse: { response in #expect(response.status == .ok) } @@ -88,7 +93,7 @@ struct HTTPStatusCodeJSONTests { "get": GraphQLField( type: GraphQLString, args: [ - "name": GraphQLArgument(type: GraphQLString), + "name": GraphQLArgument(type: GraphQLString) ], resolve: { _, args, _, _ in guard let name = args["name"].string else { @@ -96,7 +101,7 @@ struct HTTPStatusCodeJSONTests { } return name } - ), + ) ] ) ) @@ -105,10 +110,12 @@ struct HTTPStatusCodeJSONTests { } try await app.test(.POST, "/graphql", headers: jsonHeaders) { req in - try req.content.encode(GraphQLRequest( - query: "query getName($name: String!) { get(name: $name) }", - variables: ["name": .null] - )) + try req.content.encode( + GraphQLRequest( + query: "query getName($name: String!) { get(name: $name) }", + variables: ["name": .null] + ) + ) } afterResponse: { response in #expect(response.status == .ok) } @@ -123,9 +130,11 @@ struct HTTPStatusCodeJSONTests { } try await app.test(.POST, "/graphql", headers: jsonHeaders) { req in - try req.content.encode(GraphQLRequest( - query: "abc { hello }" - )) + try req.content.encode( + GraphQLRequest( + query: "abc { hello }" + ) + ) } afterResponse: { response in #expect(response.status == .ok) } @@ -144,7 +153,7 @@ struct HTTPStatusCodeJSONTests { resolve: { _, _, _, _ in throw GraphQLError(message: "Something went wrong") } - ), + ) ] ) ) diff --git a/Tests/GraphQLVaporTests/HTTPTests.swift b/Tests/GraphQLVaporTests/HTTPTests.swift index ebad7d2..3bf94bb 100644 --- a/Tests/GraphQLVaporTests/HTTPTests.swift +++ b/Tests/GraphQLVaporTests/HTTPTests.swift @@ -1,10 +1,11 @@ import GraphQL import GraphQLTransportWS -@testable import GraphQLVapor import GraphQLWS import Testing import VaporTesting +@testable import GraphQLVapor + @Suite struct HTTPTests { @Test func query() async throws { @@ -35,7 +36,7 @@ struct HTTPTests { "greet": GraphQLField( type: GraphQLString, args: [ - "name": GraphQLArgument(type: GraphQLString), + "name": GraphQLArgument(type: GraphQLString) ], resolve: { _, args, _, _ in guard let name = args["name"].string else { @@ -43,7 +44,7 @@ struct HTTPTests { } return "Hello, \(name)" } - ), + ) ] ) ) @@ -88,7 +89,7 @@ struct HTTPTests { } return ctx.message } - ), + ) ] ) ) @@ -145,7 +146,8 @@ struct HTTPTests { @Test func defaultAcceptHeader() async throws { try await withApp { app in - app.graphql(schema: helloWorldSchema, config: .init(allowMissingAcceptHeader: true)) { _ in + app.graphql(schema: helloWorldSchema, config: .init(allowMissingAcceptHeader: true)) { + _ in EmptyContext() } @@ -168,7 +170,8 @@ struct HTTPTests { EmptyContext() } - try await app.test(.GET, "/graphql?query=%7Bhello%7D", headers: jsonGraphQLHeaders) { _ in + try await app.test(.GET, "/graphql?query=%7Bhello%7D", headers: jsonGraphQLHeaders) { + _ in } afterResponse: { response in #expect(response.status == .ok) @@ -190,7 +193,8 @@ struct HTTPTests { EmptyContext() } - try await app.test(.GET, "/graphql?query=%7Bhello%7D", headers: jsonGraphQLHeaders) { _ in + try await app.test(.GET, "/graphql?query=%7Bhello%7D", headers: jsonGraphQLHeaders) { + _ in } afterResponse: { response in #expect(response.status == .methodNotAllowed) } @@ -205,20 +209,29 @@ struct HTTPTests { try await app.test(.GET, "/graphql") { response in #expect(response.status == .ok) - #expect(response.body.string == GraphiQLHandler.html(url: "/graphql", subscriptionUrl: nil)) + #expect( + response.body.string + == GraphiQLHandler.html(url: "/graphql", subscriptionUrl: nil) + ) } } } @Test func graphiqlSubscription() async throws { try await withApp { app in - app.graphql(schema: helloWorldSchema, config: .init(subscriptionProtocols: [.websocket])) { _ in + app.graphql( + schema: helloWorldSchema, + config: .init(subscriptionProtocols: [.websocket]) + ) { _ in EmptyContext() } try await app.test(.GET, "/graphql") { response in #expect(response.status == .ok) - #expect(response.body.string == GraphiQLHandler.html(url: "/graphql", subscriptionUrl: "/graphql")) + #expect( + response.body.string + == GraphiQLHandler.html(url: "/graphql", subscriptionUrl: "/graphql") + ) } } } diff --git a/Tests/GraphQLVaporTests/Utilities.swift b/Tests/GraphQLVaporTests/Utilities.swift index 1a3f810..8bace33 100644 --- a/Tests/GraphQLVaporTests/Utilities.swift +++ b/Tests/GraphQLVaporTests/Utilities.swift @@ -20,7 +20,7 @@ let helloWorldSchema = try! GraphQLSchema( resolve: { _, _, _, _ in "World" } - ), + ) ] ) ) diff --git a/Tests/GraphQLVaporTests/WebSocketTests.swift b/Tests/GraphQLVaporTests/WebSocketTests.swift index 50fc9da..306d305 100644 --- a/Tests/GraphQLVaporTests/WebSocketTests.swift +++ b/Tests/GraphQLVaporTests/WebSocketTests.swift @@ -1,10 +1,11 @@ import GraphQL import GraphQLTransportWS -@testable import GraphQLVapor import GraphQLWS import Testing import VaporTesting +@testable import GraphQLVapor + @Suite struct WebSocketTests { @Test func subscription() async throws { @@ -22,7 +23,7 @@ struct WebSocketTests { subscribe: { _, _, _, _ in await pubsub.subscribe() } - ), + ) ] ) ) @@ -45,26 +46,40 @@ struct WebSocketTests { do { #expect(!message.starts(with: "44")) let response = try #require(message.data(using: .utf8)) - if let _ = try? decoder.decode(GraphQLTransportWS.ConnectionAckResponse.self, from: response) { - try await websocket.send(#""" - { - "type": "subscribe", - "payload": { - "query": "subscription { hello }" - }, - "id": "1" - } - """#) + if (try? decoder.decode( + GraphQLTransportWS.ConnectionAckResponse.self, + from: response + )) != nil { + try await websocket.send( + #""" + { + "type": "subscribe", + "payload": { + "query": "subscription { hello }" + }, + "id": "1" + } + """# + ) // Must wait for a few milliseconds for the subscription to get set up. try await Task.sleep(for: .milliseconds(10)) await pubsub.emit(event: "World") - } else if let next = try? decoder.decode(GraphQLTransportWS.NextResponse.self, from: response) { + } else if let next = try? decoder.decode( + GraphQLTransportWS.NextResponse.self, + from: response + ) { #expect(next.payload?.errors == []) #expect(next.payload?.data == ["hello": "World"]) await pubsub.cancel() - } else if let _ = try? decoder.decode(GraphQLTransportWS.CompleteResponse.self, from: response) { + } else if (try? decoder.decode( + GraphQLTransportWS.CompleteResponse.self, + from: response + )) != nil { try await websocket.close() - } else if let _ = try? decoder.decode(GraphQLTransportWS.ErrorResponse.self, from: response) { + } else if (try? decoder.decode( + GraphQLTransportWS.ErrorResponse.self, + from: response + )) != nil { Issue.record("Error message: \(message)") await pubsub.cancel() try await websocket.close() @@ -103,7 +118,7 @@ struct WebSocketTests { subscribe: { _, _, _, _ in await pubsub.subscribe() } - ), + ) ] ) ) @@ -145,26 +160,40 @@ struct WebSocketTests { do { #expect(!message.starts(with: "44")) let response = try #require(message.data(using: .utf8)) - if let _ = try? decoder.decode(GraphQLTransportWS.ConnectionAckResponse.self, from: response) { - try await websocket.send(#""" - { - "type": "subscribe", - "payload": { - "query": "subscription { hello }" - }, - "id": "1" - } - """#) + if (try? decoder.decode( + GraphQLTransportWS.ConnectionAckResponse.self, + from: response + )) != nil { + try await websocket.send( + #""" + { + "type": "subscribe", + "payload": { + "query": "subscription { hello }" + }, + "id": "1" + } + """# + ) // Must wait for a few milliseconds for the subscription to get set up. try await Task.sleep(for: .milliseconds(10)) await pubsub.emit(event: "World") - } else if let _ = try? decoder.decode(GraphQLTransportWS.NextResponse.self, from: response) { + } else if (try? decoder.decode( + GraphQLTransportWS.NextResponse.self, + from: response + )) != nil { Issue.record("Expected Error: \(message)") await pubsub.cancel() - } else if let _ = try? decoder.decode(GraphQLTransportWS.CompleteResponse.self, from: response) { + } else if (try? decoder.decode( + GraphQLTransportWS.CompleteResponse.self, + from: response + )) != nil { Issue.record("Expected Error: \(message)") try await websocket.close() - } else if let errorResult = try? decoder.decode(GraphQLTransportWS.ErrorResponse.self, from: response) { + } else if let errorResult = try? decoder.decode( + GraphQLTransportWS.ErrorResponse.self, + from: response + ) { #expect(errorResult.payload[0].message == "Unauthorized") await pubsub.cancel() try await websocket.close() @@ -179,7 +208,9 @@ struct WebSocketTests { } do { // Send incorrect code, expect an "Unauthorized" error on the subscribe call - try await websocket.send(#"{"type": "connection_init", "payload": {"code": "def"}}"#) + try await websocket.send( + #"{"type": "connection_init", "payload": {"code": "def"}}"# + ) try await websocket.onClose.get() } catch { Issue.record("WebSocket error: \(error)") @@ -204,7 +235,7 @@ struct WebSocketTests { subscribe: { _, _, _, _ in await pubsub.subscribe() } - ), + ) ] ) ) @@ -230,26 +261,39 @@ struct WebSocketTests { do { #expect(!message.starts(with: "44")) let response = try #require(message.data(using: .utf8)) - if let _ = try? decoder.decode(GraphQLWS.ConnectionAckResponse.self, from: response) { - try await websocket.send(#""" - { - "type": "start", - "payload": { - "query": "subscription { hello }" - }, - "id": "1" - } - """#) + if (try? decoder.decode( + GraphQLWS.ConnectionAckResponse.self, + from: response + )) != nil { + try await websocket.send( + #""" + { + "type": "start", + "payload": { + "query": "subscription { hello }" + }, + "id": "1" + } + """# + ) // Must wait for a few milliseconds for the subscription to get set up. try await Task.sleep(for: .milliseconds(10)) await pubsub.emit(event: "World") - } else if let next = try? decoder.decode(GraphQLWS.DataResponse.self, from: response) { + } else if let next = try? decoder.decode( + GraphQLWS.DataResponse.self, + from: response + ) { #expect(next.payload?.errors == []) #expect(next.payload?.data == ["hello": "World"]) await pubsub.cancel() - } else if let _ = try? decoder.decode(GraphQLWS.CompleteResponse.self, from: response) { + } else if (try? decoder.decode( + GraphQLWS.CompleteResponse.self, + from: response + )) != nil { try await websocket.close() - } else if let _ = try? decoder.decode(GraphQLWS.ErrorResponse.self, from: response) { + } else if (try? decoder.decode(GraphQLWS.ErrorResponse.self, from: response)) + != nil + { Issue.record("Error message: \(message)") await pubsub.cancel() try await websocket.close()