title: Debugging order: 4#
Debugging#
We've tried to make debugging in urql as seamless as possible by creating tools for users of urql
and those creating their own exchanges.
Devtools#
It's easiest to debug urql with the urql devtools.
It offers tools to inspect internal "Debug Events" as they happen, to explore data as your app is seeing it, and to quickly trigger GraphQL queries.
For instructions on how to set up the devtools, check out @urql/devtools's readme in its
repository.
Debug events#
The "Debug Events" are internally what displays more information to the user on the devtools' "Events" tab than just Operations and Operation Results.
Events may be fired inside exchanges to add additional development logging to an exchange.
The fetchExchange for instance will fire a fetchRequest event when a request is initiated and
either a fetchError or fetchSuccess event when a result comes back from the GraphQL API.
The Devtools aren't the only way to observe these internal events.
Anyone can start listening to these events for debugging events by calling the
Client's client.subscribeToDebugTarget() method.
Unlike Operations these events are fire-and-forget events that are only used for debugging. Hence,
they shouldn't be used for anything but logging and not for messaging. Debug events are also
entirely disabled in production.
Subscribing to Debug Events#
Internally the devtoolsExchange calls the client.subscribeToDebugTarget, but if we're looking to
build custom debugging tools, it's also possible to call this function directly and to replace the
devtoolsExchange.
const { unsubscribe } = client.subscribeToDebugTarget(event => {
if (event.source === 'cacheExchange')
return;
console.log(event); // { type, message, operation, data, source, timestamp }
});
As demonstrated above, the client.subscribeToDebugTarget accepts a callback function and returns
a subscription with an unsubscribe method. We've seen this pattern in the prior "Stream Patterns"
section on the "Architecture" page.
Adding your own Debug Events#
Debug events are a means of sharing implementation details to consumers of an exchange. If you're
creating an exchange and want to share relevant information with the devtools, then you may want
to start adding your own events.
Dispatching an event#
On the "Authoring Exchanges" page we've learned about the ExchangeInput
object, which comes with a client and a forward property.
It also contains a dispatchDebug property.
It is called with an object containing the following properties:
| Prop | Type | Description |
|---|---|---|
type |
string |
A unique type identifier for the Debug Event. |
message |
string |
A human readable description of the event. |
operation |
Operation |
The Operation that the event targets. |
data |
?object |
This is an optional payload to include any data that may become useful for debugging. |
For instance, we may call dispatchDebug with our fetchRequest event. This is the event that the
fetchExchange uses to notify us that a request has commenced:
export const fetchExchange: Exchange = ({ forward, dispatchDebug }) => {
// ...
return ops$ => {
return pipe(
ops$,
// ...
mergeMap(operation => {
dispatchDebug({
type: 'fetchRequest',
message: 'A network request has been triggered',
operation,
data: {
/* ... */
},
});
// ...
})
);
};
};
If we're adding new events that aren't included in the main urql repository and are using
TypeScript, we may also declare a fixed type for the data property, so we can guarantee a
consistent payload for our Debug Events. This also prevents accidental conflicts.
// urql.d.ts
import '@urql/core';
declare module '@urql/core' {
interface DebugEventTypes {
customEventType: { somePayload: string };
}
}
Read more about extending types, like urql's DebugEventTypes on the TypeScript docs on
declaration merging.
Tips#
Lastly, in summary, here are a few tips, that are important when we're adding new Debug Events to custom exchanges:
- ✅ Share internal details: Frequent debug messages on key events inside your exchange are very
useful when later inspecting them, e.g. in the
devtools. - ✅ Create unique event types : Key events should be easily identifiable and have a unique names.
- ❌ Don't listen to debug events inside your exchange: While it's possible to call
client.subscribeToDebugTargetin an exchange it's only valuable when creating a debugging exchange, like thedevtoolsExchange. - ❌ Don't send warnings in debug events: Informing your user about warnings isn't effective
when the event isn't seen. You should still rely on
console.warnso all users see your important warnings.