Skip to main content

realtime data with GraphQL subscriptions / apollo-server

using Apollo server:




1. server.js


const {
ApolloServer,
gql,
AuthenticationError,
PubSub
} = require('apollo-server')

const pubsub = new PubSub()


const server = new ApolloServer({
typeDefs,
resolvers,
formatError: error => {
console.log(JSON.stringify(error))
return { ...error }
},

introspection: true,
playground: true,
context: async ({ req, connection }) => {
if (connection) {
return { pubsub }
}

if (req) {
const me = await getMe(req)

return {
me,
secret: process.env.SECRET,
pubsub
}
}
}
})


2. schema: project.js

extend type Subscription {
projectAdded: Project
}
3. resolver: project.js

const PROJECT_CHANNEL = 'PROJECT_CHANNEL'
Mutation: {
addProject: combineResolvers(
isAuthenticated,
async (parent, { projectInput }, { models, me, pubsub }) => {
const { projectName, clientId } = projectInput
const project = await Project.create({
accountId: me.accountId,
projectName: projectName || 'default project',
clientId: clientId || 0
})

console.log(me.accountId)
if (me.accountId === 'sat')
pubsub.publish('PROJECT_CHANNEL', { projectAdded: project })

return project
}
),
Subscription: {
projectAdded: {
subscribe: (parent, args, { pubsub }) => {
return pubsub.asyncIterator(PROJECT_CHANNEL)
}
}
}
4. front end App.js

const wsLink = new WebSocketLink({
uri: REACT_APP_WSURI,
options: {
reconnect: true
}
})
const uploadLink = createUploadLink({ uri: REACT_APP_GRAPHQL_URL })

const terminatingLink = split(
({ query }) => {
const { kind, operation } = getMainDefinition(query)
return kind === 'OperationDefinition' && operation === 'subscription'
},
wsLink,
uploadLink
)

const link = ApolloLink.from([authLink, terminatingLink])

5. Front end: dashboard.js

const { loading, error, data, refetch, subscribeToMore } = useQuery(
GET_PROJECTS
)

<ProjectList
styles={styles}
projects={projects}
navigation={navigation}
onRefresh={onRefresh}
refreshing={refreshing}
onEditProject={onEditProject}
onDeleteProject={onDeleteProject}
subscribeToNewProject={() =>
subscribeToMore({
document: ADD_PROJECT_SUBSCRIPTION,
variables: {},
updateQuery: (prev, { subscriptionData }) => {
if (!subscriptionData.data) return prev
const newProject = subscriptionData.data.projectAdded
console.log(newProject)
return Object.assign({}, prev, {
projects: [newProject, ...prev.projects]
})
}
})
}
/>

6.  project-list.js

componentDidMount () {
this.props.subscribeToNewProject()
}


Comments

Popular posts from this blog

About GraphQL - Downside

Web caching complexity

File uploading. Since GraphQL doesn’t understand files, a file uploading feature is not included in its specification. You won’t have to deal with this limitation in case of REST, as there you can POST or PUT whatever content you want to.
To allow file uploads in your GraphQL web app, there are several options: using Base64 encoding. But it will make the request larger and expensive to encode/decode.making a separate API endpoint just for this purpose.using a library like Apollo for implementing the GraphQL multipart request specification.uploadFileToS3:combineResolvers( // isAuthenticated, async (parent, args, { models }) => { const { file } = awaitargs const { createReadStream, filename, mimetype, encoding } = awaitfile conststream = createReadStream() constresult = awaituploadFileToS3(filename, stream) returnresult } ),