-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
[Modern] Subscriptions and live queries docs and examples #1655
Comments
The todo-modern example helps me a lot when I am learning the modern relay API. I think it's a perfect candidate for showing GraphQL subscription capabilities. |
Subscription and live query require a different server side support from normal GraphQL query/mutation. Relay supports the semantics/API but it relies you to give the actual server side support. relay/packages/relay-compiler/core/__tests__/fixtures/flow-generator/roots.input.rql Lines 19 to 25 in d94380a
relay/packages/relay-runtime/subscription/requestRelaySubscription.js Lines 21 to 28 in 15a7ebb
If your server supports subscription, you could pass the subscription function here
For live query, Relay currently supports polling-based 'live' query. You could specify a poll interval in the cache configure
|
Is there an example we could find somewhere that implements subscriptions using relay modern? Also note that it's exported as |
Any updates on finding an example that uses relay modern subscriptions? Would be super super handy to have an example we could all checkout 😃 |
The same thing for Live Queries would be appreciated. |
@JenniferWang Is there any chance you could track down the Environment object displayed here: https://facebook.github.io/relay/docs/subscriptions.html That'd be super awesome :) |
I'm wondering the same. I'm interested in seeing a working example/snippet of Relay Modern Subscriptions using a websocket. As seen in the link, I've worked up an example that can accept a subscription through the
The issue is that I have no idea how to connect a websocket to receive the servers response, and later parsing the response into the Relay Modern Store. |
@jamesone the |
@macolsson Just like |
@JenniferWang Thanks for the pointer. I'll look to revise the websocket logic. I've been looking at using the OnNext method from the observer, however I'm not able to figure out exactly what I'm supposed to call it with; Are there are example structures that I could follow? Not sure I can fully recreate based on Flow. |
@macolsson You should definitely look at the Flow type. I don't know if we have example implementation of a |
iirc the subscription handler should call onNext with the payload received from the server, the object with |
@JenniferWang I've followed the @josephsavona Seems like that would be something to try; source I'll give it a go! |
@josephsavona Your recollection was indeed accurate. I have the below code which gets validated and accepted in the onNext call-chain:
So that part seems to work great! However, the data does not get updated; am I required to build my own |
@macolsson Hmm, the first thing I would check is that the data matches up with the subscription itself. For mutations ansnsubscriptions, records with an |
@josephsavona Of course! I had some silly test data in the response. I've updated the faked server response to match the initial response from the GraphQL server. It seems to work great. Thank you for all your help! |
@macolsson Hey when you've got a working copy of your subscriptions network layer? Would you mind sharing it? |
Share as a PR to the docs! ;-) |
@jamesone Will do. @josephsavona I'll see what we can do! |
ping @jamesone @josephsavona I’ll just write down how I’ve approached this issue after the assistance found in this thread. It might be usable for someone else. If anyone has any comments, suggestions or anything on the below code or reasoning, do let me know. I tried adding some comments when writing the code, hope some of it makes sense. Firstly I built a The We create new subscriptions through
Whenever the server sends a subscription response the This approach requires the server to return a message such as:
I do not know if this is a great way of handling subscriptions, but it works for now with my current setup. This is doable because the method passed into the network subscription function will handle all interactions through the SubscriptionHandler. Some code: NetworkLayer
SubscriptionHandler.js
|
Cool! Thanks for sharing, that high-level approach makes sense. The main thing that stands out is that the server shouldn't have to send the query/variables back in every response. Instead, you can send a unique identifier for the query as part of the initial message to the server, then have the server just send back GraphQL payload + that identifier. A simple incrementing integer would work for that. It would also avoid the overhead of getHash(). |
Awesome, I'll have a play around with it soon! @macolsson Just out of curiosity, what are you using subscriptions for? |
@josephsavona We're currently using the hash to store the query/variables in the backend, so that we can at any time run a query and return the results of this query to every single client that is listening to the query/variable pairs. The has is currently used to key the cache-store in the back-end as well, as was initially thought as an extra layer of validation; send q/v and hash, compare, receive q/v and hash, compare. But it might be redundant. We're still looking into different approaches. @jamesone We'll be using it to update multiple clients on data mutation (not just the client who performs the mutation) and we're using it to stream real-time data from hardware to mobile app to backend. |
@bochen2014 are you gonna open source your work any time soon? |
I just managed to make subscriptions work with Relay Modern as well. Note that I'm not using Here's my minimal setup code: Environment.jsimport { SubscriptionClient } from 'subscriptions-transport-ws'
const {
Environment,
Network,
RecordSource,
Store,
} = require('relay-runtime')
const store = new Store(new RecordSource())
const fetchQuery = (operation, variables) => {
return fetch('https://api.graph.cool/relay/v1/__GRAPHCOOL_PROJECT_ID__', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: operation.text,
variables,
}),
}).then(response => {
return response.json()
})
}
const websocketURL = 'wss://subscriptions.graph.cool/v1/__GRAPHCOOL_PROJECT_ID__'
function setupSubscription(
config,
variables,
cacheConfig,
observer,
) {
const query = config.text
const subscriptionClient = new SubscriptionClient(websocketURL, {reconnect: true})
const id = subscriptionClient.subscribe({query, variables}, (error, result) => {
observer.onNext({data: result})
})
}
const network = Network.create(fetchQuery, setupSubscription)
const environment = new Environment({
network,
store,
})
export default environment NewLinkSubscription.jsimport {
graphql,
requestSubscription
} from 'react-relay'
import environment from '../Environment'
const newLinkSubscription = graphql`
subscription NewLinkSubscription {
Link {
mutation
node {
id
description
url
createdAt
postedBy {
id
name
}
}
}
}
`
export default (onNext, onError, onCompleted, updater) => {
const subscriptionConfig = {
subscription: newLinkSubscription,
variables: {},
onError,
onNext,
onCompleted,
updater
}
requestSubscription(
environment,
subscriptionConfig
)
} Now you can simply use the exported function to subscribe. For example, in one of my React components in componentDidMount() {
NewLinkSubscription(
response => console.log(`Received data: `, response),
error => console.log(`An error occurred:`, error),
() => console.log(`Completed`)
)
} Note that the |
@nikolasburk thanks, this is great! |
@nikolasburk Care to submit a PR to document that approach? |
@hkjorgensen Great point about the schema file! You're right that our Relay API currently doesn't support subscriptions. What I did to satisfy the Relay Compiler was actually manually copying over the @josephsavona Will do that soon! |
Perhaps this should be split into two tickets: one for live queries, one for subscriptions. I have a live query question though: |
@idris Relay Modern uses |
@nikolasburk |
Check out https://facebook.github.io/relay/docs/subscriptions.html which explains Also as an update, all networks now accept I'm closing this issue since it's quite old, but if anyone would like to contribute to the documentation, we're always interested in reviewing those PRs. |
the guys at graphcool also have this tutorial up: https://www.howtographql.com/react-apollo/8-subscriptions/ just sharing for future people who find this |
@nikolasburk subscriptionClient.subscribe is no longer a function: apollographql/subscriptions-transport-ws#261 Do you know how to fix that? |
I havent' tried it myself but I believe it should be possible to replace the |
According to docs we can use the const subscriptionClient = new SubscriptionClient(websocketUrl, {reconnect: true})
const onNext = (result) => {
observer.onNext(result)
}
const onError = (error) => {
observer.onError(error)
}
const onComplete = () => {
observer.onCompleted()
}
const client = subscriptionClient
.request({ query, variables })
.subscribe(onNext, onError, onComplete) |
@slaviczavik Where are you pulling the observer from? |
@perrosnk It was response on @nikolasburk code. This is full code: import { Environment, Network, RecordSource, Store } from 'relay-runtime'
import { SubscriptionClient } from 'subscriptions-transport-ws'
const endpoint = 'http://your-endpoint:3000/graphql'
const websocketUrl = 'ws://your-endpoint:3000/subscriptions'
const setupSubscription = (config, variables, cacheConfig, observer) => {
const query = config.text
const subscriptionClient = new SubscriptionClient(websocketUrl, {reconnect: true})
const onNext = (result) => {
observer.onNext(result)
}
const onError = (error) => {
observer.onError(error)
}
const onComplete = () => {
observer.onCompleted()
}
const client = subscriptionClient.request({ query, variables }).subscribe(
onNext,
onError,
onComplete
)
// client.unsubscribe()
}
const fetchQuery = (operation, variables, cacheConfig, uploadebles) => {
return fetch(endpoint, {
method: 'POST',
credentials: 'include',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
query: operation.text,
variables
})
}).then(response => {
return response.json()
})
}
const network = Network.create(
fetchQuery,
setupSubscription
)
const source = new RecordSource()
const store = new Store(source)
const environment = new Environment({
network,
store
})
export default environment |
SubscriptionClient has been removed from the latest versions 'subscriptions-transport-ws'. |
I’m pretty sure it’s still there. |
Yes excuse my shortcut, SubscriptionManager support has been removed which broke the previous implementations proposed in this thread. |
The docs claim that Relay supports subscriptions and live queries, but there are no examples provided or documentation.
https://facebook.github.io/relay/docs/new-in-relay-modern.html#graphql-subscriptions-live-queries
The text was updated successfully, but these errors were encountered: