Skip to content

Commit 156a270

Browse files
committed
Added subscriptions to graphql example
1 parent 27004e1 commit 156a270

File tree

5 files changed

+114
-7
lines changed

5 files changed

+114
-7
lines changed

examples/graphql/dev-server.js

+43-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
require('@babel/polyfill');
2+
const { createServer } = require('http');
3+
24
const express = require('express');
35
const webpack = require('webpack');
46
const webpackDevMiddleware = require('webpack-dev-middleware');
5-
const { ApolloServer, gql } = require('apollo-server-express');
7+
const { ApolloServer, gql, PubSub } = require('apollo-server-express');
68

79
const webpackConfig = require('./webpack.config');
810

11+
const pubsub = new PubSub();
12+
913
const app = express();
1014

1115
app.use(
@@ -29,6 +33,8 @@ const books = [
2933
},
3034
];
3135

36+
let numberOfBookLikes = 0;
37+
3238
const typeDefs = gql`
3339
type Book {
3440
id: ID!
@@ -46,6 +52,7 @@ const typeDefs = gql`
4652
type Query {
4753
books: [Book!]!
4854
book(id: ID!): Book
55+
numberOfBookLikes: Int!
4956
}
5057
5158
type Mutation {
@@ -55,14 +62,26 @@ const typeDefs = gql`
5562
singleUpload(file: Upload!): File!
5663
multipleUpload(files: [Upload!]!): [File!]!
5764
}
65+
66+
type Subscription {
67+
onBookLiked: Int!
68+
}
5869
`;
5970

6071
const findBookById = id => books.find(book => book.id === id);
6172

73+
const ON_BOOK_LIKED = 'ON_BOOK_LIKED';
74+
6275
const resolvers = {
6376
Query: {
6477
books: () => books,
6578
book: (_, args) => findBookById(args.id),
79+
numberOfBookLikes: () => numberOfBookLikes,
80+
},
81+
Subscription: {
82+
onBookLiked: {
83+
subscribe: () => pubsub.asyncIterator([ON_BOOK_LIKED]),
84+
},
6685
},
6786
Mutation: {
6887
deleteBook: (_, args) => findBookById(args.id),
@@ -74,6 +93,8 @@ const resolvers = {
7493
}
7594

7695
book.liked = true;
96+
numberOfBookLikes += 1;
97+
pubsub.publish(ON_BOOK_LIKED, { onBookLiked: numberOfBookLikes });
7798
return book;
7899
},
79100
unlikeBook: (_, args) => {
@@ -99,13 +120,32 @@ const resolvers = {
99120
},
100121
};
101122

123+
// const sleep = () => new Promise(resolve => setTimeout(resolve, 50));
124+
102125
const server = new ApolloServer({
103126
typeDefs,
104127
resolvers,
128+
subscriptions: {
129+
// onConnect: async connectionParams => {
130+
// if (connectionParams.token === 'pass') {
131+
// await sleep();
132+
133+
// return {
134+
// currentUser: 'user',
135+
// };
136+
// }
137+
138+
// throw new Error('Missing auth token!');
139+
// },
140+
keepAlive: 10000,
141+
},
105142
});
106143

107-
server.applyMiddleware({ app });
144+
server.applyMiddleware({ app, path: '/graphql' });
145+
146+
const httpServer = createServer(app);
147+
server.installSubscriptionHandlers(httpServer);
108148

109-
app.listen(3000, () => {
149+
httpServer.listen(3000, () => {
110150
console.log('Listening on port 3000!');
111151
});

examples/graphql/src/components/app.jsx

+28-2
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,33 @@
11
import React from 'react';
2-
import { useDispatch } from 'react-redux';
3-
import { Query, Mutation } from '@redux-requests/react';
2+
import { useDispatch, useSelector } from 'react-redux';
3+
import { getWebsocketState } from '@redux-requests/core';
4+
import {
5+
Query,
6+
Mutation,
7+
useQuery,
8+
useSubscription,
9+
} from '@redux-requests/react';
410

511
import {
12+
fetchNumberOfBookLikes,
613
fetchBooks,
714
fetchBook,
815
deleteBook,
916
likeBook,
1017
unlikeBook,
1118
uploadFile,
1219
uploadFiles,
20+
onBookLiked,
1321
} from '../store/actions';
1422
import {
23+
FETCH_NUMBER_OF_BOOK_LIKES,
1524
LIKE_BOOK,
1625
UNLIKE_BOOK,
1726
FETCH_BOOK,
1827
FETCH_BOOKS,
1928
UPLOAD_FILE,
2029
UPLOAD_FILES,
30+
ON_BOOK_LIKED,
2131
} from '../store/constants';
2232

2333
import Spinner from './spinner';
@@ -30,10 +40,26 @@ const RequestError = () => (
3040

3141
const App = () => {
3242
const dispatch = useDispatch();
43+
const websocketState = useSelector(getWebsocketState);
44+
const { data } = useQuery({
45+
type: FETCH_NUMBER_OF_BOOK_LIKES,
46+
action: fetchNumberOfBookLikes,
47+
autoLoad: true,
48+
});
49+
50+
useSubscription({
51+
type: ON_BOOK_LIKED,
52+
action: onBookLiked,
53+
});
3354

3455
return (
3556
<div>
3657
<h1>Redux Requests GraphQL example</h1>
58+
<div>
59+
WS: {websocketState.connected ? 'connected' : 'disconnected'},{' '}
60+
{websocketState.pristine ? 'pristine' : 'not pristine'}{' '}
61+
</div>
62+
{data && <div>Number of likes: {data.numberOfBookLikes}</div>}
3763
<p>
3864
In order to see aborts in action, you should set network throttling in
3965
your browser

examples/graphql/src/store/actions.js

+31
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { gql } from '@redux-requests/graphql';
22

33
import {
4+
FETCH_NUMBER_OF_BOOK_LIKES,
45
FETCH_BOOKS,
56
FETCH_BOOK,
67
DELETE_BOOK,
78
LIKE_BOOK,
89
UNLIKE_BOOK,
10+
ON_BOOK_LIKED,
911
UPLOAD_FILE,
1012
UPLOAD_FILES,
1113
} from './constants';
@@ -18,6 +20,17 @@ const bookFragment = gql`
1820
}
1921
`;
2022

23+
export const fetchNumberOfBookLikes = () => ({
24+
type: FETCH_NUMBER_OF_BOOK_LIKES,
25+
request: {
26+
query: gql`
27+
{
28+
numberOfBookLikes
29+
}
30+
`,
31+
},
32+
});
33+
2134
export const fetchBooks = () => ({
2235
type: FETCH_BOOKS,
2336
request: {
@@ -125,6 +138,24 @@ export const unlikeBook = id => ({
125138
},
126139
});
127140

141+
export const onBookLiked = () => ({
142+
type: ON_BOOK_LIKED,
143+
subscription: {
144+
query: gql`
145+
subscription {
146+
onBookLiked
147+
}
148+
`,
149+
},
150+
meta: {
151+
mutations: {
152+
[FETCH_NUMBER_OF_BOOK_LIKES]: (data, subscriptionData) => ({
153+
numberOfBookLikes: subscriptionData.onBookLiked,
154+
}),
155+
},
156+
},
157+
});
158+
128159
const fileFragment = gql`
129160
fragment FileFragment on File {
130161
filename
+2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
export const FETCH_BOOKS = 'FETCH_BOOKS';
22
export const FETCH_BOOK = 'FETCH_BOOK';
3+
export const FETCH_NUMBER_OF_BOOK_LIKES = 'FETCH_NUMBER_OF_BOOK_LIKES';
34
export const DELETE_BOOK = 'DELETE_BOOK';
45
export const LIKE_BOOK = 'LIKE_BOOK';
56
export const UNLIKE_BOOK = 'UNLIKE_BOOK';
67
export const UPLOAD_FILE = 'UPLOAD_FILE';
78
export const UPLOAD_FILES = 'UPLOAD_FILES';
9+
export const ON_BOOK_LIKED = 'ON_BOOK_LIKED';

examples/graphql/src/store/index.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
22
import { handleRequests } from '@redux-requests/core';
3-
import { createDriver } from '@redux-requests/graphql';
3+
import { createDriver, createSubscriber } from '@redux-requests/graphql';
44

55
export const configureStore = () => {
66
const { requestsReducer, requestsMiddleware } = handleRequests({
7-
driver: createDriver({ url: 'http://localhost:3000/graphql' }),
7+
driver: createDriver({
8+
url: 'http://localhost:3000/graphql',
9+
}),
10+
subscriber: createSubscriber({
11+
url: 'ws://localhost:3000/graphql',
12+
// lazy: false,
13+
heartbeatTimeout: 12,
14+
useHeartbeat: true,
15+
}),
816
});
917

1018
const reducers = combineReducers({

0 commit comments

Comments
 (0)