https://github.com/graphqlswift/graphqltransportws
Swift implementation of the graphql-transport-ws WebSocket subprotocol.
https://github.com/graphqlswift/graphqltransportws
Last synced: 15 days ago
JSON representation
Swift implementation of the graphql-transport-ws WebSocket subprotocol.
- Host: GitHub
- URL: https://github.com/graphqlswift/graphqltransportws
- Owner: GraphQLSwift
- License: mit
- Created: 2022-07-08T21:31:02.000Z (almost 4 years ago)
- Default Branch: main
- Last Pushed: 2026-05-17T23:23:01.000Z (15 days ago)
- Last Synced: 2026-05-18T00:24:24.353Z (15 days ago)
- Language: Swift
- Homepage:
- Size: 89.8 KB
- Stars: 3
- Watchers: 3
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# GraphQLTransportWS
[](https://swiftpackageindex.com/GraphQLSwift/GraphQLTransportWS)
[](https://swiftpackageindex.com/GraphQLSwift/GraphQLTransportWS)
This implements the [graphql-transport-ws WebSocket subprotocol](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md).
It is mainly intended for server support, but there is a basic client implementation included.
Features:
- Server implementation that implements defined protocol conversations
- Client and Server types that wrap messengers
- Codable Server and Client message structures
- Custom authentication support
## Usage
To use this package, include it in your `Package.swift` dependencies:
```swift
.package(url: "https://github.com/GraphQLSwift/GraphQLTransportWS", from: "")
```
Then create a concrete type that conforms to the `Messenger` protocol. Here's an example using
[`WebSocketKit`](https://github.com/vapor/websocket-kit):
```swift
import WebSocketKit
import GraphQLTransportWS
/// Messenger wrapper for WebSockets
struct WebSocketMessenger: Messenger {
let websocket: WebSocket
func send(_ message: Data) async throws {
try await websocket.send(String(decoding: message, as: UTF8.self))
}
func error(_ message: String, code: Int) async throws {
try await websocket.close(code: code)
}
func close() async throws {
try await websocket.close()
}
}
```
Next create a `Server`, provide the messenger you just defined, and wrap the API `execute` and `subscribe` commands:
```swift
routes.webSocket(
"graphqlSubscribe",
onUpgrade: { request, websocket in
let messenger = WebSocketMessenger(websocket: websocket)
let server = GraphQLTransportWS.Server(
messenger: messenger,
onExecute: { graphQLRequest in
try await api.execute(
request: graphQLRequest.query,
context: context,
on: self.eventLoop,
variables: graphQLRequest.variables,
operationName: graphQLRequest.operationName
)
},
onSubscribe: { graphQLRequest in
try await api.subscribe(
request: graphQLRequest.query,
context: context,
on: self.eventLoop,
variables: graphQLRequest.variables,
operationName: graphQLRequest.operationName
)
}
)
let incoming = AsyncStream { continuation in
websocket.onText { _, message in
continuation.yield(Data(message.utf8))
}
}
try await server.listen(to: incoming)
}
)
```
### Authentication
This package exposes authentication hooks on the `connection_init` message. To perform custom authentication,
provide a codable type to the Server init and define an `auth` callback on the server. For example:
```swift
struct UsernameAndPasswordInitPayload: Equatable & Codable {
let username: String
let password: String
}
let server = GraphQLTransportWS.Server(
messenger: messenger,
onExecute: { ... },
onSubscribe: { ... }
)
server.auth { payload in
guard payload.username == "admin" else {
throw Abort(.unauthorized)
}
}
```
This example would require `connection_init` message from the client to look like this:
```json
{
"type": "connection_init",
"payload": {
"username": "admin",
"password": "supersafe"
}
}
```
If the `payload` field is not required on your server, you may make Server's generic declaration optional like `Server`