This error happens when you try to use subscriptions in your URQL app but don’t have a subscription exchange. Fix this by installing subscriptions-transport-ws
and adding the subscriptionExchange
to your URQL config.
This error was discovered when writing the real-time chat app example. If you haven’t already, you should check it out.
Let’s look at the cause of the problem.
Problem: you didn’t add a subscription exchange in your URQL config
Let’s say you’re using subscriptions, and this is your URQL client config:
import { createClient, defaultExchanges } from "urql";
export const urqlClient = createClient({
url: `http://${process.env.REACT_APP_HOSTNAME}:8000/graphql`,
exchanges: [...defaultExchanges]
});
JavaScriptThe defaultExchanges
list doesn’t contain the required subscriptionExchange
to handle subscriptions. If you try to run the app like this, you’ll get the following error on your frontend:
Solution: install the subscription transport and add the subscriptionExchange to your URQL config
To fix this, we first have to install the subscriptions-transport-ws
package using NPM:
npm install subscriptions-transport-ws
ShellScriptOnce that’s installed, we have to modify our URQL config:
import { createClient, defaultExchanges, subscriptionExchange } from "urql";
import { SubscriptionClient } from "subscriptions-transport-ws";
const subscriptionClient = new SubscriptionClient(
`ws://${process.env.REACT_APP_HOSTNAME}:8000/graphql`, {
reconnect: true,
lazy: true
});
export const urqlClient = createClient({
url: `http://${process.env.REACT_APP_HOSTNAME}:8000/graphql`,
exchanges: [
subscriptionExchange({
forwardSubscription: (operation) => subscriptionClient.request(operation)
}),
...defaultExchanges
]
});
JavaScriptWhat we did here was:
- Create and configure a
SubscriptionClient
- Add the
subscriptionExchange
to our list of exchanges
Create and configure a SubscriptionClient
The first thing we have to do is import, create, and configure the SubscriptionClient
:
import { SubscriptionClient } from "subscriptions-transport-ws";
const subscriptionClient = new SubscriptionClient(
`ws://${process.env.REACT_APP_HOSTNAME}:8000/graphql`, {
reconnect: true,
lazy: true
});
export const urqlClient = createClient({
JavaScriptThe SubscriptionClient
class can be imported from the subscriptions-transport-ws
package. Once imported, we have to instantiate and configure it. Since subscriptions use WebSockets, we have to again specify the GraphQL endpoint for our app, except instead of http
or https
, we put ws
or wss
as the transport protocol. Additional configuration options can also be passed as an object for the second argument. Here, we set reconnect: true
and lazy: true
. These control how the connection is established and maintained.
Add the subscription exchange
Next, we add our subscriptionExchange
:
export const urqlClient = createClient({
url: `http://${process.env.REACT_APP_HOSTNAME}:8000/graphql`,
exchanges: [
subscriptionExchange({
forwardSubscription: (operation) => subscriptionClient.request(operation)
}),
...defaultExchanges
]
});
JavaScriptThe subscriptionExchange
can be imported from the urql
package. To add it to our list of exchanges for this URQL client, we pass in an object with the forwardSubscription
field set to an arrow function that takes the operation as a parameter, and then passes that to the request
method of the subscriptionClient
we configured in the previous step.
Finally, we use the “splat” operator (...
) to put the rest of the defaultExchanges
in our list.
Conclusion
We covered what causes the error “No exchange has handled operations of kind subscription” and how to fix it. In short, it’s caused by not adding the subscriptionExchange
to our list of exchanges when we configured our URQL client. To do this, we also have to install subscriptions-transport-ws
and configure subscriptionExchange
to use it.
John is a professional software engineer who has been solving problems with code for 15+ years. He has experience with full stack web development, container orchestration, mobile development, DevOps, Windows and Linux kernel development, cybersecurity, and reverse engineering. In his spare time, he’s researching the potential business applications of AI.