If there's one thing we know when it comes to tech is that things change fast and all the time. New language features come, libraries, conventions, the things that are cool change, and even business requirements crop up all the time.
When creating Urql, one of the goals was to make sure that it's as flexible as possible, so it would be able to adapt to the changing tech landscape. So in order to make Urql as adaptable as possible, it's built to be as extensible as possible.
Extensibility really is at the heart of Urql, which brings us to exchanges. Urql is built on exchanges. So if you have a think about what a GraphQL client does at its core, it takes a request, a query, or a mutation, and it gives the appropriate response, so a cache hit, a response from the API, or an error. So as a result, most GraphQL clients, including Urql, are built to be stream-based. So an exchange is just a plugin that allows you to inspect and modify both the incoming and outgoing streams.
Let me show you this, by example, because that will make it a whole lot clearer. When you install Urql and execute a query, by default, Urql uses three exchanges. These come packaged into UrqlCore. So we have the dedupe, the cache, and the fetch exchanges. All of these are completely replaceable, by the way, so you can swap out any of these for custom or alternate implementation.
So first, the dedupe exchange, it removes duplicate requests when the exact request is already in flight. So imagine a website with a header and a sidebar. And both of these want to display the user's name. Both of these will use a use query with exactly the same query. What the fetch exchange, the dedupe exchange does, is it makes sure that only one instance of that query is passed on to the next exchange, and therefore, removing the need for a duplicate API request.
Then the cache exchange returns the data from the cache if there is some. And finally, the fetch exchange, which will always be in the last exchange in the array, does the actual network request and puts the result back into the output stream. Then the result is passed from the network request exchange to the cache exchange, where it is stored for next time, and finally, it's passed back to the use query result.
Now, since you can literally add an unlimited amount of plugins, the only way to guarantee that they're all playing nice with each other is to make sure each plugin remains unopinionated. Let's have a look at an actual example of this in Exchanges. First, we have the fetch exchange that we already talked about. This is the default fetch exchange included in Urql Core. It fetches the data from the API and adds to the output stream. Now, a separate package add-on, you can install a separate add-on package for automatic persisted queries in a persistent fetch exchange. So, this exchange used the same fetch logic as the actual fetch exchange. But with automatic persisted queries, basically the way it works is that it allows server-side caching of GraphQL data.
Comments