@@ -89,6 +89,102 @@ struct WebSocketTests {
8989 }
9090 }
9191
92+ @Test func subscriptionWithInitPayloadError( ) async throws {
93+ let pubsub = SimplePubSub < String > ( )
94+ let schema = try GraphQLSchema (
95+ subscription: GraphQLObjectType (
96+ name: " Subscription " ,
97+ fields: [
98+ " hello " : GraphQLField (
99+ type: GraphQLString,
100+ resolve: { source, _, _, _ in
101+ source as! String
102+ } ,
103+ subscribe: { _, _, _, _ in
104+ await pubsub. subscribe ( )
105+ }
106+ ) ,
107+ ]
108+ )
109+ )
110+
111+ struct InitPayload : Equatable , Codable , Sendable {
112+ let code : String
113+ }
114+ let acceptedCode = " abc "
115+
116+ let router = Router ( context: TestWebSocketContext . self)
117+ router. graphqlWebSocket (
118+ schema: schema,
119+ config: . init(
120+ subscriptionProtocols: [ . websocket] ,
121+ websocket: . init(
122+ onWebSocketInit: { ( initPayload: InitPayload , _, _) in
123+ initPayload. code == acceptedCode
124+ }
125+ )
126+ )
127+ ) { inputs in
128+ // If the codes don't match, this will fail on the subscribe/execute request
129+ guard let codeIsValid = inputs. websocketInitResult, codeIsValid else {
130+ throw GraphQLError ( message: " Unauthorized " )
131+ }
132+ return EmptyContext ( )
133+ }
134+ let app = Application (
135+ router: Router ( ) ,
136+ server: . http1WebSocketUpgrade( webSocketRouter: router) ,
137+ configuration: . init( address: . hostname( " 127.0.0.1 " , port: 0 ) )
138+ )
139+
140+ _ = try await app. test ( . live) { client in
141+ try await client. ws (
142+ " /graphql " ,
143+ configuration: . init( additionalHeaders: [ . secWebSocketProtocol: " graphql-transport-ws " ] )
144+ ) { inbound, outbound, _ in
145+ // Start the sequence
146+ // Send incorrect code, expect an "Unauthorized" error on the subscribe call
147+ try await outbound. write ( . text( #"{"type": "connection_init", "payload": {"code": "def"}}"# ) )
148+ for try await message in inbound. messages ( maxSize: 1024 * 1024 ) {
149+ guard case let . text( message) = message else { return }
150+ #expect( !message. starts ( with: " 44 " ) )
151+ let response = try #require( message. data ( using: . utf8) )
152+ if let _ = try ? decoder. decode ( GraphQLTransportWS . ConnectionAckResponse. self, from: response) {
153+ try await outbound. write ( . text( #"""
154+ {
155+ "type": "subscribe",
156+ "payload": {
157+ "query": "subscription { hello }"
158+ },
159+ "id": "1"
160+ }
161+ """# ) )
162+ // Must wait for a few milliseconds for the subscription to get set up.
163+ try await Task . sleep ( for: . milliseconds( 10 ) )
164+ // Force the server to emit an event
165+ await pubsub. emit ( event: " World " )
166+ } else if let _ = try ? decoder. decode ( GraphQLTransportWS . NextResponse. self, from: response) {
167+ Issue . record ( " Expected Error: \( message) " )
168+ await pubsub. cancel ( )
169+ break
170+ } else if let _ = try ? decoder. decode ( GraphQLTransportWS . CompleteResponse. self, from: response) {
171+ Issue . record ( " Expected Error: \( message) " )
172+ try await outbound. close ( . goingAway, reason: nil )
173+ break
174+ } else if let errorResult = try ? decoder. decode ( GraphQLTransportWS . ErrorResponse. self, from: response) {
175+ #expect( errorResult. payload [ 0 ] . message == " Unauthorized " )
176+ await pubsub. cancel ( )
177+ try await outbound. close ( . goingAway, reason: nil )
178+ break
179+ } else {
180+ Issue . record ( " Unrecognized message: \( message) " )
181+ break
182+ }
183+ }
184+ }
185+ }
186+ }
187+
92188 @Test func subscription_GraphQLWS( ) async throws {
93189 let pubsub = SimplePubSub < String > ( )
94190 let schema = try GraphQLSchema (
0 commit comments