Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add graphql-ws protocol support #2168

Merged
merged 21 commits into from
Feb 25, 2022
Merged
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
6e7af18
Implement graphql-transport-ws protocol support
calvincestari Feb 18, 2022
d60ae4a
Add graphql-transport-ws integration test based on Apollo Server docs…
calvincestari Feb 18, 2022
685d359
Add CI step for Apollo Server graphql-transport-ws tests
calvincestari Feb 18, 2022
c36b779
After installing node v12 switch to use v16
calvincestari Feb 18, 2022
b1fc644
Instruct nvm to use version in .nvmrc
calvincestari Feb 18, 2022
6768fde
Update documentation and tutorial
calvincestari Feb 18, 2022
e8d1123
Change WSProtocol cases to closer match library names
calvincestari Feb 21, 2022
7f6c4b6
Remove initializer defaults and require web socket protocol on design…
calvincestari Feb 21, 2022
ad9fbb5
Update Subscriptions documentation
calvincestari Feb 21, 2022
37336c5
Add WSProtocol option for AWS AppSync
calvincestari Feb 22, 2022
348dcf0
Add ping/pong message support required by graphql-ws
calvincestari Feb 22, 2022
3391f33
Update documentation and tutorial
calvincestari Feb 23, 2022
5b3aafb
Add tests for subscriptionWsProtocol
calvincestari Feb 24, 2022
6edea9b
Add tests for graphqlWSProtocol
calvincestari Feb 24, 2022
4178c66
Revert to naming aligned with the protocols and not the implementatio…
calvincestari Feb 24, 2022
d63d078
Use longer async timeout for slower environments like CI
calvincestari Feb 24, 2022
fa3f459
Fix test names
calvincestari Feb 24, 2022
118745d
Fix project configuration
calvincestari Feb 25, 2022
3589cad
Rename protocol parameter on WebSocket initializers
calvincestari Feb 25, 2022
2a92350
Revert "Use longer async timeout for slower environments like CI"
calvincestari Feb 25, 2022
9c92529
Fix async timing bug and refactor websocket protocol tests
calvincestari Feb 25, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Implement graphql-transport-ws protocol support
calvincestari committed Feb 18, 2022
commit 6e7af189609213b2570fa54c7c51e79ca590e0c5
34 changes: 27 additions & 7 deletions Sources/ApolloWebSocket/DefaultImplementation/WebSocket.swift
Original file line number Diff line number Diff line change
@@ -68,14 +68,25 @@ public final class WebSocket: NSObject, WebSocketClient, StreamDelegate, WebSock
public let code: Int
}

private struct Constants {
public enum WSProtocol: CustomStringConvertible {
case graphql_ws
case graphql_transport_ws

public var description: String {
switch self {
case .graphql_ws: return "graphql-ws"
case .graphql_transport_ws: return "graphql-transport-ws"
}
}
}

struct Constants {
static let headerWSUpgradeName = "Upgrade"
static let headerWSUpgradeValue = "websocket"
static let headerWSHostName = "Host"
static let headerWSConnectionName = "Connection"
static let headerWSConnectionValue = "Upgrade"
static let headerWSProtocolName = "Sec-WebSocket-Protocol"
static let headerWSProtocolValue = "graphql-ws"
static let headerWSVersionName = "Sec-WebSocket-Version"
static let headerWSVersionValue = "13"
static let headerWSExtensionName = "Sec-WebSocket-Extensions"
@@ -197,20 +208,29 @@ public final class WebSocket: NSObject, WebSocketClient, StreamDelegate, WebSock
self.request.setValue(origin, forHTTPHeaderField: Constants.headerOriginName)
}

self.request.setValue(Constants.headerWSProtocolValue,
forHTTPHeaderField: Constants.headerWSProtocolName)
if self.request.value(forHTTPHeaderField: Constants.headerWSProtocolName) == nil {
self.request.setValue(WSProtocol.graphql_ws.description,
forHTTPHeaderField: Constants.headerWSProtocolName)
}
writeQueue.maxConcurrentOperationCount = 1
}

public convenience init(url: URL) {
public convenience init(url: URL, webSocketProtocol: WSProtocol = .graphql_ws) {
var request = URLRequest(url: url)
request.timeoutInterval = 5
request.setValue(webSocketProtocol.description,
forHTTPHeaderField: Constants.headerWSProtocolName)

self.init(request: request)
}

// Used for specifically setting the QOS for the write queue.
public convenience init(url: URL, writeQueueQOS: QualityOfService) {
self.init(url: url)
public convenience init(
url: URL,
writeQueueQOS: QualityOfService,
webSocketProtocol: WSProtocol = .graphql_ws
) {
self.init(url: url, webSocketProtocol: webSocketProtocol)
writeQueue.qualityOfService = writeQueueQOS
}

4 changes: 3 additions & 1 deletion Sources/ApolloWebSocket/OperationMessage.swift
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ final class OperationMessage {
enum Types : String {
case connectionInit = "connection_init" // Client -> Server
case connectionTerminate = "connection_terminate" // Client -> Server
case subscribe = "subscribe" // Client -> Server
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Messages that are additive so that we can continue to support both protocols.

case start = "start" // Client -> Server
case stop = "stop" // Client -> Server

@@ -17,6 +18,7 @@ final class OperationMessage {
case data = "data" // Server -> Client
case error = "error" // Server -> Client
case complete = "complete" // Server -> Client
case next = "next" // Server -> Client
}

let serializationFormat = JSONSerializationFormat.self
@@ -34,7 +36,7 @@ final class OperationMessage {

init(payload: GraphQLMap? = nil,
id: String? = nil,
type: Types = .start) {
type: Types) {
var message: GraphQLMap = [:]
if let payload = payload {
message["payload"] = payload
10 changes: 9 additions & 1 deletion Sources/ApolloWebSocket/WebSocketTransport.swift
Original file line number Diff line number Diff line change
@@ -145,6 +145,7 @@ public class WebSocketTransport {

switch messageType {
case .data,
.next,
.error:
if let id = parseHandler.id, let responseHandler = subscribers[id] {
if let payload = parseHandler.payload {
@@ -185,6 +186,7 @@ public class WebSocketTransport {

case .connectionInit,
.connectionTerminate,
.subscribe,
.start,
.stop,
.connectionError:
@@ -270,7 +272,13 @@ public class WebSocketTransport {
sendQueryDocument: true,
autoPersistQuery: false)
let identifier = operationMessageIdCreator.requestId()
guard let message = OperationMessage(payload: body, id: identifier).rawMessage else {

var type: OperationMessage.Types = .start
if case WebSocket.WSProtocol.graphql_transport_ws.description = websocket.request.value(forHTTPHeaderField: WebSocket.Constants.headerWSProtocolName) {
type = .subscribe
}

guard let message = OperationMessage(payload: body, id: identifier, type: type).rawMessage else {
return nil
}