Skip to content

Commit 6a3e7ab

Browse files
nuragicAllan Jorge
and
Allan Jorge
authored
feat: add fullWsTransport support (#767)
* feat: add fullWsTransport support * fix: remove redundant else clauses Co-authored-by: Allan Jorge <[email protected]>
1 parent 06dade3 commit 6a3e7ab

File tree

12 files changed

+340
-11
lines changed

12 files changed

+340
-11
lines changed

README.md

+5-2
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,11 @@ const client = new GraphQLClient(config)
142142

143143
**`config`**: Object containing configuration properties
144144

145-
- `url` (**Required**): The url to your GraphQL server
145+
- `url`: The URL of your GraphQL **HTTP** server. If not specified, you must enable `fullWsTransport` and provide a valid `subscriptionClient`; otherwise is **required**.
146+
- `fullWsTransport`: Boolean - set to `true` if you want to use `subscriptionClient` to also send query and mutations via WebSocket; defaults to `false`
146147
- `ssrMode`: Boolean - set to `true` when using on the server for server-side rendering; defaults to `false`
147148
- `useGETForQueries`: Boolean - set to `true` to use HTTP GET method for all queries; defaults to false. See [HTTP Get Support](#HTTP-Get-support) for more info
148-
- `subscriptionClient`: An instance of `SubscriptionClient` from [subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws) or `Client` from [graphql-ws](https://github.com/enisdenjo/graphql-ws). A factory function can also be passed in order to avoid the creation of the client in ssr environments.
149+
- `subscriptionClient`: The **WebSocket** client configuration. Accepts either an instance of `SubscriptionClient` from [subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws) or `Client` from [graphql-ws](https://github.com/enisdenjo/graphql-ws). A factory function is also accepted e.g. to avoid the creation of the client in SSR environments.
149150
- `cache` (**Required** if `ssrMode` is `true`, otherwise optional): Object with the following methods:
150151
- `cache.get(key)`
151152
- `cache.set(key, data)`
@@ -454,6 +455,8 @@ function TotalCountComponent() {
454455

455456
See our [subscription example](examples/subscription) which has both the client and server code to integrate subscriptions into your application.
456457

458+
See also the [full WS transport example](examples/full-ws-transport) if you want to see how to send every operation through WebSocket.
459+
457460
# Guides
458461

459462
## SSR

examples/full-ws-transport/README.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Full WS transport Example
2+
3+
An example showing how to send every operation (subscription, query, mutation) via WebSocket.
4+
5+
## Usage
6+
7+
Run `npm start` to start the app.
8+
9+
Run `npm run server` to start the server.
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "graphql-hooks-full-ws-transport-example",
3+
"version": "0.1.0",
4+
"private": true,
5+
"dependencies": {
6+
"fastify": "^3.25.3",
7+
"graphql-hooks": "^5.5.1",
8+
"graphql-ws": "^5.5.5",
9+
"mercurius": "^9.3.0",
10+
"react": "^17.0.0",
11+
"react-dom": "^17.0.0",
12+
"react-scripts": "^5.0.0"
13+
},
14+
"scripts": {
15+
"start": "react-scripts start",
16+
"server": "node server/index.js"
17+
},
18+
"browserslist": {
19+
"production": [
20+
">0.2%",
21+
"not dead",
22+
"not op_mini all"
23+
],
24+
"development": [
25+
"last 1 chrome version",
26+
"last 1 firefox version",
27+
"last 1 safari version"
28+
]
29+
}
30+
}
3.78 KB
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<title>GraphQL hooks - Full WS transport Example</title>
7+
</head>
8+
<body>
9+
<noscript>You need to enable JavaScript to run this app.</noscript>
10+
<div id="root"></div>
11+
</body>
12+
</html>
+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import Fastify from 'fastify'
2+
import mercurius from 'mercurius'
3+
4+
const app = Fastify({ logger: true })
5+
6+
let x = 0
7+
8+
const schema = `
9+
type ResultChange {
10+
operation: String
11+
prev: Int
12+
current: Int
13+
}
14+
type Query {
15+
result: Int
16+
}
17+
type Mutation {
18+
add(num: Int): Int
19+
subtract(num: Int): Int
20+
}
21+
type Subscription {
22+
onResultChange: ResultChange
23+
}
24+
`
25+
26+
const resolvers = {
27+
Query: {
28+
result: async () => {
29+
return x
30+
}
31+
},
32+
Mutation: {
33+
add: async (_, args, { pubsub }) => {
34+
const prev = x
35+
const { num } = args
36+
37+
x = prev + num
38+
39+
pubsub.publish({
40+
topic: 'RESULT_TOPIC',
41+
payload: {
42+
onResultChange: {
43+
operation: 'add',
44+
prev,
45+
current: x
46+
}
47+
}
48+
})
49+
50+
return x
51+
},
52+
subtract: async (_, args, { pubsub }) => {
53+
const prev = x
54+
const { num } = args
55+
56+
x = prev - num
57+
58+
pubsub.publish({
59+
topic: 'RESULT_TOPIC',
60+
payload: {
61+
onResultChange: {
62+
operation: 'subtract',
63+
prev,
64+
current: x
65+
}
66+
}
67+
})
68+
69+
return x
70+
}
71+
},
72+
Subscription: {
73+
onResultChange: {
74+
subscribe: async (_, __, { pubsub }) => {
75+
return await pubsub.subscribe('RESULT_TOPIC')
76+
}
77+
}
78+
}
79+
}
80+
81+
app.register(mercurius, {
82+
schema,
83+
resolvers,
84+
graphiql: true,
85+
subscription: {
86+
fullWsTransport: true
87+
}
88+
})
89+
90+
app.listen(4000)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "module"
3+
}

examples/full-ws-transport/src/App.js

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import React, { useState } from 'react'
2+
import { useQuery, useMutation, useSubscription } from 'graphql-hooks'
3+
4+
const RESULT = `query GetResult {
5+
result
6+
}`
7+
8+
const ADD = `mutation AddValue($num: Int) {
9+
add(num: $num)
10+
}`
11+
12+
const SUBTRACT = `mutation SubtractValue($num: Int) {
13+
subtract(num: $num)
14+
}`
15+
16+
const ON_RESULT_CHANGE = `subscription OnResultChange {
17+
onResultChange {
18+
operation
19+
prev
20+
current
21+
}
22+
}`
23+
24+
export default function App() {
25+
const { isLoading, data, refetch } = useQuery(RESULT)
26+
27+
const [addMutation] = useMutation(ADD)
28+
29+
const [subtractMutation] = useMutation(SUBTRACT)
30+
31+
const [resultState, setResultState] = useState({
32+
operation: '',
33+
prev: '',
34+
current: ''
35+
})
36+
37+
useSubscription(
38+
{
39+
query: ON_RESULT_CHANGE
40+
},
41+
({ data: { onResultChange }, errors }) => {
42+
if (errors && errors.length > 0) {
43+
console.log(errors[0])
44+
}
45+
if (onResultChange) {
46+
setResultState(onResultChange)
47+
refetch()
48+
}
49+
}
50+
)
51+
52+
return (
53+
<div className="app">
54+
<div className="count">
55+
<h1>{isLoading ? 'Loading…' : data?.result}</h1>
56+
</div>
57+
<div className="buttons">
58+
<button
59+
onClick={() => {
60+
return subtractMutation({ variables: { num: 1 } })
61+
}}
62+
>
63+
-
64+
</button>
65+
<button
66+
onClick={() => {
67+
return addMutation({ variables: { num: 1 } })
68+
}}
69+
>
70+
+
71+
</button>
72+
</div>
73+
<pre>{JSON.stringify(resultState, null, 2)}</pre>
74+
</div>
75+
)
76+
}
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
body {
2+
margin: 0;
3+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5+
sans-serif;
6+
-webkit-font-smoothing: antialiased;
7+
-moz-osx-font-smoothing: grayscale;
8+
}
9+
10+
pre {
11+
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12+
monospace;
13+
font-size: 24px;
14+
}
15+
16+
.app {
17+
display: flex;
18+
flex-direction: column;
19+
align-items: center;
20+
justify-content: center;
21+
height: 100vh;
22+
font-size: 48px;
23+
}
24+
25+
.buttons button {
26+
font-size: 60px;
27+
width: 80px;
28+
height: 80px;
29+
margin: 0 40px;
30+
}
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React from 'react'
2+
import ReactDOM from 'react-dom'
3+
import { createClient } from 'graphql-ws'
4+
import { GraphQLClient, ClientContext } from 'graphql-hooks'
5+
import App from './App'
6+
7+
import './index.css'
8+
9+
const subscriptionClient = createClient({
10+
url: 'ws://localhost:4000/graphql',
11+
lazy: false
12+
})
13+
14+
const client = new GraphQLClient({
15+
fullWsTransport: true,
16+
subscriptionClient
17+
})
18+
19+
ReactDOM.render(
20+
<React.StrictMode>
21+
<ClientContext.Provider value={client}>
22+
<App />
23+
</ClientContext.Provider>
24+
</React.StrictMode>,
25+
document.getElementById('root')
26+
)

0 commit comments

Comments
 (0)