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
Show file tree
Hide file tree
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
3 changes: 3 additions & 0 deletions Sources/ApolloWebSocket/DefaultImplementation/WebSocket.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,11 @@ public final class WebSocket: NSObject, WebSocketClient, StreamDelegate, WebSock
public let code: Int
}

/// The WebSocket sub-protocols supported.
public enum WSProtocol: CustomStringConvertible {
calvincestari marked this conversation as resolved.
Show resolved Hide resolved
/// Protocol implemented by the graphql-ws library.
case graphql_ws
/// Protocol implemented by the subscriptions-transport-ws libary - considered legacy.
case graphql_transport_ws

public var description: String {
Expand Down
20 changes: 16 additions & 4 deletions docs/source/subscriptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ There are two different classes which conform to the [`NetworkTransport` protoco

Typically, you'll want to use `SplitNetworkTransport`, since this allows you to retain the single `NetworkTransport` setup and avoids any potential issues of using multiple client objects.

## GraphQL over WebSocket Protocols

There are two WebSocket sub-protocols that apollo-ios supports:
1. [graphql-transport-ws](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md) which is implemented in the [graphql-ws](https://github.com/enisdenjo/graphql-ws) package. This is a modern, actively maintained package and is our recommendation to use in your server.
2. [graphql-ws](https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md) which is implemented in the [subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws) package. This is considered a legacy implementation and is not recommended for new server builds.

It is important to note that the two libraries and protocols are not cross-compatible. You will need to know which sub-protocol is implemented in the server you're connecting to.

There are a number of ways to specify which sub-protocol apollo-ios should use:
1. Manually specify the protocol in the `Sec-WebSocket-Protocol` header of a `URLRequest`. This must be done before initializing a WebSocket using `WebSocket(request:)` as apollo-ios will look for the header key and if found it will use that protocol otherwise it will default to using the `graphql-transport-ws`. See `WebSocket.WSProtocol` for the header values.
2. Use one of the convenience initializers `WebSocket(url:webSocketProtocol:)` or `WebSocket(url:writeQueueQOS:webSocketProtocol:)` where you can specify the protocol on initialization.

Using `graphql-transport-ws` as the default may seem odd since it's considered a legacy protocol but this was done to not force a breaking change to pre-existing apps using apollo-ios.

## Sample subscription-supporting initializer

Here is an example of setting up a singleton similar to the [Example Advanced Client Setup](initialization/#advanced-client-creation), but which uses a `SplitNetworkTransport` to support both subscriptions and queries:
Expand All @@ -36,8 +50,7 @@ class Apollo {
/// A web socket transport to use for subscriptions
private lazy var webSocketTransport: WebSocketTransport = {
let url = URL(string: "ws://localhost:8080/websocket")!
let request = URLRequest(url: url)
let webSocketClient = WebSocket(request: request)
let webSocketClient = WebSocket(url: url, webSocketProtocol: .graphql_ws)
return WebSocketTransport(websocket: webSocketClient)
}()

Expand Down Expand Up @@ -161,8 +174,7 @@ class Apollo {
// initializes the connection as an authorized channel.
private lazy var webSocketTransport: WebSocketTransport = {
let url = URL(string: "ws://localhost:8080/websocket")!
let request = URLRequest(url: url)
let webSocketClient = WebSocket(request: request)
let webSocketClient = WebSocket(url: url, webSocketProtocol: .graphql_ws)
let authPayload = ["authToken": magicToken]
return WebSocketTransport(websocket: webSocketClient, connectingPayload: authPayload)
}()
Expand Down
11 changes: 8 additions & 3 deletions docs/source/tutorial/tutorial-subscriptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,19 @@ Next, in the lazy declaration of the `apollo` variable, immediately after `trans

```swift:title=Network.swift
// 1
let webSocket = WebSocket(url: URL(string: "wss://apollo-fullstack-tutorial.herokuapp.com/graphql")!)
let webSocket = WebSocket(
url: URL(string: "wss://apollo-fullstack-tutorial.herokuapp.com/graphql")!,
webSocketProtocol: .graphql_ws
)

// 2
let webSocketTransport = WebSocketTransport(websocket: webSocket)

// 3
let splitTransport = SplitNetworkTransport(uploadingNetworkTransport: transport,
webSocketNetworkTransport: webSocketTransport)
let splitTransport = SplitNetworkTransport(
uploadingNetworkTransport: transport,
webSocketNetworkTransport: webSocketTransport
)

// 4
return ApolloClient(networkTransport: splitTransport, store: store)
Expand Down