Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.

(docs) - Replace "Main Concepts" section with "Architecture" and "Authoring Exchanges" pages (#1418)

* Move "Document Caching" and "Errors" to "Basics"

* Add new "Architecture" page

* Move "Exchanges" page to "Advanced"

* Remove "Main Concepts" section

* Apply suggestions from code review

Co-authored-by: Will Golledge <35961363+wgolledge@users.noreply.github.com>

Co-authored-by: Will Golledge <35961363+wgolledge@users.noreply.github.com>

+4 -5
docs/README.md
···
customized GraphQL infrastructure. In short, `urql` prioritizes usability and adaptability.
As you're adopting GraphQL, `urql` becomes your primary data layer and can handle content-heavy
-
pages through ["Document Caching"](./concepts/document-caching.md) as well as dynamic and data-heavy
apps through ["Normalized Caching"](./graphcache/normalized-caching.md).
`urql` can be understood as a collection of connected parts and packages.
···
`@urql/core`](./basics/core.md), which we can imagine as the brain
of `urql` with most of its logic. As we progress with implementing `urql` into our application,
we're later able to extend it by adding ["addon packages", which we call
-
_Exchanges_](./concepts/exchanges.md)
If at this point you're still unsure of whether to use `urql`, [have a look at the **Comparison**
page](./comparison.md) and check whether `urql` supports all features you're looking for.
···
- **Basics** is the section where we'll want to start learning about `urql` as it contains "Getting
Started" guides for our framework of choice.
-
- **Main Concepts** then explains more about how `urql` functions, what it's made up of, and covers
-
the main aspects of the `Client` and GraphQL clients in general, on the ["Philosophy"
-
page](./concepts/philosophy.md).
- **Advanced** covers all more uncommon use-cases and contains guides that we won't need immediately
when we get started with `urql`.
- **Graphcache** documents one of the most important addons to `urql`, which adds ["Normalized
···
customized GraphQL infrastructure. In short, `urql` prioritizes usability and adaptability.
As you're adopting GraphQL, `urql` becomes your primary data layer and can handle content-heavy
+
pages through ["Document Caching"](./basics/document-caching.md) as well as dynamic and data-heavy
apps through ["Normalized Caching"](./graphcache/normalized-caching.md).
`urql` can be understood as a collection of connected parts and packages.
···
`@urql/core`](./basics/core.md), which we can imagine as the brain
of `urql` with most of its logic. As we progress with implementing `urql` into our application,
we're later able to extend it by adding ["addon packages", which we call
+
_Exchanges_](./advanced/authoring-exchanges.md)
If at this point you're still unsure of whether to use `urql`, [have a look at the **Comparison**
page](./comparison.md) and check whether `urql` supports all features you're looking for.
···
- **Basics** is the section where we'll want to start learning about `urql` as it contains "Getting
Started" guides for our framework of choice.
+
- **Architecture** then explains more about how `urql` functions, what it's made up of, and covers
+
the main aspects of the `Client` and exchanges.
- **Advanced** covers all more uncommon use-cases and contains guides that we won't need immediately
when we get started with `urql`.
- **Graphcache** documents one of the most important addons to `urql`, which adds ["Normalized
+5 -2
docs/advanced/README.md
···
# Advanced
In this chapter we'll dive into various topics of "advanced" `urql` usage. This is admittedly a
-
catch-all chapter of various use-cases that can only be covered after [the "Concepts"
-
chapter.](../concepts/README.md)
- [**Subscriptions**](./subscriptions.md) covers how to use `useSubscription` and how to set up GraphQL subscriptions with
`urql`.
···
- [**Retrying operations**](./retry-operations.md) shows the `retryExchange` which allows you to retry operations when they've failed.
- [**Authentication**](./authentication.md) describes how to implement authentication using the `authExchange`
- [**Testing**](./testing.md) covers how to test components that use `urql` particularly in React.
- [**Auto-populate Mutations**](./auto-populate-mutations.md) presents the `populateExchange` addon which can make it easier to
update normalized data after mutations.
···
# Advanced
In this chapter we'll dive into various topics of "advanced" `urql` usage. This is admittedly a
+
catch-all chapter of various use-cases that can only be covered after [the "Architecture"
+
chapter.](../architecture.md)
- [**Subscriptions**](./subscriptions.md) covers how to use `useSubscription` and how to set up GraphQL subscriptions with
`urql`.
···
- [**Retrying operations**](./retry-operations.md) shows the `retryExchange` which allows you to retry operations when they've failed.
- [**Authentication**](./authentication.md) describes how to implement authentication using the `authExchange`
- [**Testing**](./testing.md) covers how to test components that use `urql` particularly in React.
+
- [**Authoring Exchanges**](./authoring-exchanges.md) describes how to implement exchanges from
+
scratch and how they work internally. This is a good basis to understanding how some of the
+
features in this section function.
- [**Auto-populate Mutations**](./auto-populate-mutations.md) presents the `populateExchange` addon which can make it easier to
update normalized data after mutations.
+1 -1
docs/advanced/auto-populate-mutations.md
···
---
title: Auto-populate Mutations
-
order: 8
---
# Automatically populating Mutations
···
---
title: Auto-populate Mutations
+
order: 9
---
# Automatically populating Mutations
+2 -2
docs/advanced/debugging.md
···
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.](../concepts/stream-patterns.md#the-wonka-library)
## Adding your own Debug Events
···
#### Dispatching an event
-
In the ["Exchanges" section](../concepts/exchanges.md) we've learned about the [`ExchangeInput`
object](../api/core.md#exchangeinput), which comes with a `client` and a `forward` property.
It also contains a `dispatchDebug` property.
···
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.](../architecture.md)
## Adding your own Debug Events
···
#### Dispatching an event
+
[On the "Authoring Exchanges" page](./authoring-exchanges.md) we've learned about the [`ExchangeInput`
object](../api/core.md#exchangeinput), which comes with a `client` and a `forward` property.
It also contains a `dispatchDebug` property.
+7 -3
docs/advanced/subscriptions.md
···
});
```
-
[Read more about _Exchanges_ and how they work on the "Exchanges" page.](../concepts/exchanges.md)
In the above example, we add the `subscriptionExchange` to the `Client` with the default exchanges
add before it. The `subscriptionExchange` is a factory that accepts additional options and returns
···
## One-off Subscriptions
-
When you're using subscriptions directly without `urql`'s framework bindings, you can use the `Client`'s `subscription` method for one-off subscriptions. This method is similar to the ones for mutations and subscriptions [that we've seen before on the "Core Package" page.](../concepts/core-package.md#one-off-queries-and-mutations)
-
This method will always [returns a Wonka stream](../concepts/stream-patterns.md#the-wonka-library) and doesn't have a `.toPromise()` shortcut method, since promises won't return the multiple values that a subscription may deliver. Let's convert the above example to one without framework code, as we may use subscriptions in a Node.js environment.
```js
import { pipe, subscribe } from 'wonka';
···
});
```
+
Read more about Exchanges and how they work [on the "Authoring Exchanges"
+
page.](./authoring-exchanges.md) or what they are [on the "Architecture"
+
page.](../architecture.md)
In the above example, we add the `subscriptionExchange` to the `Client` with the default exchanges
add before it. The `subscriptionExchange` is a factory that accepts additional options and returns
···
## One-off Subscriptions
+
When you're using subscriptions directly without `urql`'s framework bindings, you can use the
+
`Client`'s `subscription` method for one-off subscriptions. This method is similar to the ones for
+
mutations and subscriptions [that we've seen before on the "Core Package" page.](../basics/core.md)
+
This method will always [returns a Wonka stream](../architecture.md#the-wonka-library) and doesn't have a `.toPromise()` shortcut method, since promises won't return the multiple values that a subscription may deliver. Let's convert the above example to one without framework code, as we may use subscriptions in a Node.js environment.
```js
import { pipe, subscribe } from 'wonka';
+4 -1
docs/advanced/testing.md
···
- `useMutation` calls `executeMutation`
- `useSubscription` calls `executeSubscription`
-
In the section [Stream Patterns](../concepts/stream-patterns.md) we've seen, that all methods on the client operate with and return streams. These streams are created using the [Wonka](../concepts/stream-patterns.md#the-wonka-library) library and we're able to create streams ourselves to mock the different states of our operations, e.g. fetching, errors, or success with data.
You'll probably use one of these utility functions to create streams:
···
- `useMutation` calls `executeMutation`
- `useSubscription` calls `executeSubscription`
+
In the section ["Stream Patterns" on the "Architecture" page](../architecture.md) we've seen, that
+
all methods on the client operate with and return streams. These streams are created using
+
[the Wonka library](../architecture.md#the-wonka-library) and we're able to create streams
+
ourselves to mock the different states of our operations, e.g. fetching, errors, or success with data.
You'll probably use one of these utility functions to create streams:
+1 -1
docs/api/README.md
···
package or exchange packages, which are all listed in this section.
Most of these packages will refer to or use utilities and types from the `@urql/core` package. [Read
-
more about the core package on the "Core Package" page.](../concepts/core-package.md)
- [`@urql/core` API docs](./core.md)
- [`urql` React API docs](./urql.md)
···
package or exchange packages, which are all listed in this section.
Most of these packages will refer to or use utilities and types from the `@urql/core` package. [Read
+
more about the core package on the "Core" page.](../basics/core.md)
- [`@urql/core` API docs](./core.md)
- [`urql` React API docs](./urql.md)
+9 -9
docs/api/core.md
···
Therefore if you're not accessing utilities directly, aren't in a Node.js environment, and are using
framework bindings, you'll likely want to import from your framework bindings package directly.
-
[Read more about `urql`'s core on the "Core Package" page.](../concepts/core-package.md)
## Client
···
```
[Read more about how to use this API on the "Core Package"
-
page.](../concepts/core-package.md#one-off-queries-and-mutations)
### client.mutation
This is similar to [`client.query`](#clientquery), but dispatches mutations instead.
[Read more about how to use this API on the "Core Package"
-
page.](../concepts/core-package.md#one-off-queries-and-mutations)
### client.subscription
···
| `graphQLErrors` | `?Array<string \| GraphQLError>` | GraphQL Errors (if any) that were returned by the GraphQL API |
| `response` | `?any` | The raw response object (if any) from the `fetch` call |
-
[Read more about errors in `urql` on the "Error" page.](../concepts/errors.md)
## Types
···
- `'network-only'`
- `'cache-and-network'`
-
[Read more about request policies on the "Document Caching" page.](../concepts/document-caching.md#request-policies)
### OperationContext
···
An exchange represents abstractions of small chunks of logic in `urql`.
They're small building blocks and similar to "middleware".
-
[Read more about _Exchanges_ on the "Exchanges" page.](../concepts/exchanges.md)
An exchange is defined to be a function that receives [`ExchangeInput`](#exchangeinput) and returns
an `ExchangeIO` function. The `ExchangeIO` function in turn will receive a stream of operations, and
···
type Exchange = ExchangeInput => ExchangeIO;
```
-
[If you haven't yet seen `Source`, read more about "Stream
-
Patterns".](../concepts/stream-patterns.md)
## Exchanges
### cacheExchange
-
The `cacheExchange` as [described on the "Document Caching" page.](../concepts/document-caching.md). It's of type `Exchange`.
### subscriptionExchange
···
Therefore if you're not accessing utilities directly, aren't in a Node.js environment, and are using
framework bindings, you'll likely want to import from your framework bindings package directly.
+
[Read more about `urql`'s core on the "Core Package" page.](../basics/core.md)
## Client
···
```
[Read more about how to use this API on the "Core Package"
+
page.](../basics/core.md#one-off-queries-and-mutations)
### client.mutation
This is similar to [`client.query`](#clientquery), but dispatches mutations instead.
[Read more about how to use this API on the "Core Package"
+
page.](../basics/core.md#one-off-queries-and-mutations)
### client.subscription
···
| `graphQLErrors` | `?Array<string \| GraphQLError>` | GraphQL Errors (if any) that were returned by the GraphQL API |
| `response` | `?any` | The raw response object (if any) from the `fetch` call |
+
[Read more about errors in `urql` on the "Error" page.](../basics/errors.md)
## Types
···
- `'network-only'`
- `'cache-and-network'`
+
[Read more about request policies on the "Document Caching" page.](../basics/document-caching.md#request-policies)
### OperationContext
···
An exchange represents abstractions of small chunks of logic in `urql`.
They're small building blocks and similar to "middleware".
+
[Read more about _Exchanges_ on the "Authoring Exchanges" page.](../advanced/authoring-exchanges.md)
An exchange is defined to be a function that receives [`ExchangeInput`](#exchangeinput) and returns
an `ExchangeIO` function. The `ExchangeIO` function in turn will receive a stream of operations, and
···
type Exchange = ExchangeInput => ExchangeIO;
```
+
[If you haven't yet seen streams you can read more about "Stream Patterns" on the "Architecture"
+
page.](../architecture.md)
## Exchanges
### cacheExchange
+
The `cacheExchange` as [described on the "Document Caching" page.](../basics/document-caching.md). It's of type `Exchange`.
### subscriptionExchange
+1 -1
docs/api/request-policy-exchange.md
···
that may be used to upgrade [Operations' Request Policies](./core.md#requestpolicy) on a
time-to-live basis.
-
[Read more about request policies on the "Document Caching" page.](../concepts/document-caching.md#request-policies)
This exchange will conditionally upgrade `cache-first` and `cache-only` operations to use
`cache-and-network`, so that the client gets an opportunity to update its cached data, when the
···
that may be used to upgrade [Operations' Request Policies](./core.md#requestpolicy) on a
time-to-live basis.
+
[Read more about request policies on the "Document Caching" page.](../basics/document-caching.md#request-policies)
This exchange will conditionally upgrade `cache-first` and `cache-only` operations to use
`cache-and-network`, so that the client gets an opportunity to update its cached data, when the
+245
docs/architecture.md
···
···
+
---
+
title: Architecture
+
order: 3
+
---
+
+
# Architecture
+
+
`urql` is a highly customizable and flexible GraphQL client, that happens to come with some default
+
[core behavior in the core package](./core-package.md).
+
+
By default, `urql` aims to provide the minimal amount of features that allow us to build an app
+
quickly. However, `urql` has also been designed to be a GraphQL Client
+
that grows with our usage and demands. As we go from building our smallest or first GraphQL apps to
+
utilising its full functionality, we have tools at our disposal to extend and customize `urql` to
+
our liking.
+
+
## Using GraphQL Clients
+
+
You may have worked with a GraphQL API previously and noticed that using GraphQL in your app can be
+
as straightforward as sending a plain HTTP request with your query to fetch some data.
+
+
GraphQL also provides an opportunity to abstract away a lot of the manual work that goes with
+
sending these queries and managing the data. Ultimately, this lets you focus on building
+
your app without having to handle the technical details of state management in detail.
+
+
Specifically, `urql` simplifies three common aspects of using GraphQL:
+
+
- Sending queries and mutations and receiving results _declaratively_
+
- Abstracting _caching_ and state management internally
+
- Providing a central point of _extensibility_ and integration with your API
+
+
In the following sections we'll talk about the way that `urql` solves these three problems and how the logic abstracted away internally.
+
+
## Requests and Operations on the Client
+
+
If `urql` was a train it would take several stops to arrive at its terminus, our API. It starts with us
+
defining queries or mutations. Any GraphQL request can be abstracted into their query documents and
+
their variables. In `urql`, these GraphQL requests are treated as unique objects which are uniquely
+
identified by the query document and variables (which is why a `key` is generated from the two). This
+
`key` is a hash number of the query document and variables and uniquely identifies our
+
[`GraphQLRequest`](./api/core.md#graphqlrequest).
+
+
Whenever we decide to send a request to our API we start by using `urql`'s
+
[`Client`](./api/core.md#client). It accepts several options like `url` or `requestPolicy` which are
+
extra information on how the GraphQL requests are executed.
+
+
```js
+
import { Client } from '@urql/core';
+
+
new Client({
+
url: '/graphql',
+
requestPolicy: 'cache-first',
+
})
+
```
+
+
The bindings that we've seen in [the "Basics" section](./basics/README.md) interact with [the
+
`Client`](./api/core.md#client) directly and are a thin abstraction on top of it. Though some methods can be called on it directly, as seen [on the "Core Usage"
+
page](./basics/core.md#one-off-queries-and-mutations).
+
+
When we send our queries or mutations to the `Client`, internally they will be managed as
+
[`Operation`s.](./api/core.md#operation). An "Operation" is an extension of `GraphQLRequest`s. Not
+
only do they carry the `query`, `variables`, and a `key` property, they will also identify the
+
`kind` of operation that is executed, like `"query"` or `"mutation"`. We can also find the
+
`Client`'s options on `operation.context` which carries an operation's metadata.
+
+
![Operations and Results](./assets/urql-event-hub.png)
+
+
It's the `Client`s responsibility to accept an `Operation` and execute it. The bindings interally
+
call the `client.executeQuery`, `client.executeMutation`, or `client.executeSubscription` methods
+
and we'll get a "stream" of results. This "stream" allows us to register a callback with it to
+
receive results.
+
+
In the diagram we can see that each operation is a signal for our request to start at which point
+
we can expect to receive our results eventually on a callback. Once we're not interested in results
+
anymore a special "teardown" signal is issued on the `Client`. While we don't see operations outside
+
of the `Client`, they're what travel through the "Exchanges" on the `Client`.
+
+
## The Client and Exchanges
+
+
To reiterate, when we use `urql`'s bindings for our framework of choice, methods are called on the
+
`Client` but we never see the operations that are created in the background from our bindings. We
+
call a method like `client.executeQuery` (or it's called for us in the bindings), an operation is
+
issued internally when we subscribe with a callback, and later our callback is called with results.
+
+
![Operations stream and results stream](./assets/urql-client-architecture.png)
+
+
While we know that, for us, we're only interested in a single [`Operation`](./api/core.md#operation)
+
and its [`OperationResult`s](./api/core.md#operationresult) at a time, the `Client` treats these as
+
one big stream. The `Client` sees an incoming flow of all of our operations.
+
+
As we've learned before, each operation carries a `key` and each result we receive carries the
+
original `operation`. Because an `OperationResult` also carries an `operation` property the `Client`
+
will always know which results correspond to an individual operation.
+
However, internally, all of our operations are processed at the same time concurrently. However from
+
our perspective:
+
+
- We subscribe to a "stream" and expect to get results on a callback
+
- The `Client` issues the operation and we'll receive some results back eventually as either the
+
cache responds (synchronously) or the request gets sent to our API.
+
- We eventually unsubscribe and the `Client` issues a "teardown" operation with the same `key` as
+
the original operation, which concludes our flow.
+
+
The `Client` itself doesn't actually know what to do with operations. Instead, it sends them through
+
"exchanges". Exchanges are akin to [middleware in Redux](https://redux.js.org/advanced/middleware)
+
and have access to all operations and all results. Multiple exchanges are chained to process our
+
operations and to execute logic on them, one of them being the `fetchExchange`, which as the name
+
implies sends our requests to our API.
+
+
### How operations get to exchanges
+
+
We now know how we get to operations and to the `Client`:
+
+
- Any bindings or calls to the `Client` create an **operation**
+
- This operation identifies itself as either a `"query"`, `"mutation"` or `"subscription"` and has a
+
unique `key`.
+
- This operation is sent into the **exchanges** and eventually ends up at the `fetchExchange`
+
(or a similar exchange)
+
- The operation is sent to the API and a **result** comes back which is wrapped in an `OperationResult`
+
- The `Client` filters the `OperationResult` by the `operation.key` and — via a callback — gives us
+
a **stream of results**.
+
+
To come back to our train analogy from earlier, an operation, like a train, travels from one end
+
of the track to the terminus — our API. The results then come back on the same path as they're just
+
travelling the same line in reverse.
+
+
### The Exchanges
+
+
The default set of exchanges that `@urql/core` contains and applies to a `Client` are:
+
+
- `dedupExchange`: Deduplicates pending operations (pending = waiting for a result)
+
- `cacheExchange`: The default caching logic with ["Document Caching"](../basics/document-caching.md)
+
- `fetchExchange`: Sends an operation to the API using `fetch` and adds results to the output stream
+
+
When we don't pass the `exchanges` option manually to our `Client` then these are the ones that will
+
be applied. As we can see, an exchange exters a lot of power over our operations and results. They
+
determine a lot of the logic of the `Client`, taking care of things like deduplication, caching, and
+
sending requests to our API.
+
+
Some of the exchanges that are available to us are:
+
+
- [`errorExchange`](./api/core.md#errorexchange): Allows a global callback to be called when any error occurs
+
- [`ssrExchange`](./advanced/server-side-rendering.md): Allows for a server-side renderer to
+
collect results for client-side rehydration.
+
- [`retryExchange`](./advanced/retry-operations.md): Allows operations to be retried
+
- [`multipartFetchExchange`](./advanced/persistence-and-uploads.md#file-uploads): Provides multipart file upload capability
+
- [`persistedFetchExchange`](./advanced/persistence-and-uploads.md#automatic-persisted-queries): Provides support for Automatic
+
Persisted Queries
+
- [`authExchange`](./advanced/authentication.md): Allows complex authentication flows to be implemented
+
easily.
+
- [`requestPolicyExchange`](../api/request-policy-exchange.md): Automatically upgrades `cache-only` and `cache-first` operations to `cache-and-network` after a given amount of time.
+
- [`refocusExchange`](../api/refocus-exchange.md): Tracks open queries and refetches them
+
when the window regains focus.
+
- `devtoolsExchange`: Provides the ability to use the [urql-devtools](https://github.com/FormidableLabs/urql-devtools)
+
+
We can even swap out our [document cache](./basics/document-caching.md), which is implemented by
+
`@urql/core`'s `cacheExchange`, with `urql`'s [normalized cache,
+
Graphcache](./graphcache/README.md).
+
+
[Read more about exchanges and how to write them from scratch on the "Authoring Exchanges"
+
page.](./advanced/authoring-exchanges.md)
+
+
## Stream Patterns in `urql`
+
+
In the previous sections we've learned a lot about how the `Client` works, but we've always learned
+
it in vague terms — for instance, we've learned that we get a "stream of results" or `urql` sees all
+
operations as "one stream of operations" that it sends to the exchanges.
+
But, **what are streams?**
+
+
Generally we refer to _streams_ as abstractions that allow us to program with asynchronous events
+
over time. Within the JavaScript context we're thinking specifically in terms of of
+
[Observables](https://github.com/tc39/proposal-observable)
+
and [Reactive Programming with Observables.](http://reactivex.io/documentation/observable.html)
+
These concepts may sound initimidating, but from a high-level view what we're talking about can be
+
thought of as a combination of promises and iterables (e.g. arrays). We're dealing with multiple
+
events but our callback is called over time. It's like calling `forEach` on an array but expecting
+
the results to come in asynchronously.
+
+
As a user, if we're using the one framework bindings that we've seen in [the "Basics"
+
section](./basics/README.md), we may never see these streams in action or may never use them even,
+
since the bindings internally use them for us. But if we [use the `Client`
+
directly](./basics/core.md#one-off-queries-and-mutations) or write exchanges then we'll see streams
+
and wil have to deal with their API.
+
+
### The Wonka library
+
+
`urql` utilises the [Wonka](https://github.com/kitten/wonka) library for its streams. It has a
+
few advantages that are specifically tailored for the `urql` library and ecosystem:
+
+
- It is extremely lightweight and treeshakeable, with a size of around 3.7kB minzipped.
+
- It's cross-platform and cross-language compatible, having been written in
+
[Reason](https://reasonml.github.io/) and provides support for [Flow](https://flow.org/)
+
and [TypeScript](https://www.typescriptlang.org/v2/).
+
- It's a predictable and iterable toolchain, emitting synchronous events whenever possible.
+
+
Typical usage of Wonka will involve creating a _source_ of some values and a _sink_.
+
+
```js
+
import { fromArray, map, subscribe, pipe } from 'wonka';
+
+
const { unsubscribe } = pipe(
+
fromArray([1, 2, 3]),
+
map(x => x * 2),
+
subscribe(x => {
+
console.log(x); // 2, 4, 6
+
})
+
);
+
```
+
+
In Wonka, like with Observables, streams are cancellable by calling the `unsubscribe` method that a
+
subscription returns.
+
+
[Read more about Wonka in its documentation](https://wonka.kitten.sh/basics/background).
+
+
### Stream patterns with the client
+
+
When we call methods on the `Client` like [`client.executeQuery`](./api/core.md#clientexecutequery)
+
or [`client.query`](./api/core.md#clientquery) then these will return a Wonka stream. Those are
+
essentially just a bunch of callbacks.
+
+
We can use [`wonka`'s `subscribe`](https://wonka.kitten.sh/api/sinks#subscribe) function to start
+
this stream. We pass this function a callback and will receive results back from the `Client`, as it
+
starts our operation. When we unsubscribe then the `Client` will stop this operation by sending a
+
special "teardown" operation to our exchanges.
+
+
```js
+
import { pipe, subscribe } from 'wonka';
+
+
const QUERY = `
+
query Test($id: ID!) {
+
getUser(id: $id) {
+
id
+
name
+
}
+
}
+
`;
+
+
const { unsubscribe } = pipe(
+
client.query(QUERY, { id: 'test' }),
+
subscribe(result => {
+
console.log(result); // { data: ... }
+
})
+
);
+
```
+
+
Read more about the available APIs on the `Client` in the [Core API docs](../api/core.md).
+4 -5
docs/basics/README.md
···
- [**Core Package**](./core-package.md) defines why a shared package exists that contains the main
logic of `urql`, and how we can use it directly in Node.js.
-
After reading "Basics" you may want to [read the "Concepts" chapter of the
-
documentation](../concepts/README.md) as it explains the motivation and architecture that drives
-
`urql`. Two notable sections there include:
-
- [**Document Caching**](../concepts/document-caching.md) explains the default cache mechanism of `urql`, as opposed to the opt-in
[Normalized Cache](../graphcache/normalized-caching.md).
-
- [**Errors**](../concepts/errors.md) contains information on error handling in `urql`.
···
- [**Core Package**](./core-package.md) defines why a shared package exists that contains the main
logic of `urql`, and how we can use it directly in Node.js.
+
After reading the page for your bindings and the "Core" page you may want to the next two pages in
+
this section of the documentation:
+
- [**Document Caching**](./document-caching.md) explains the default cache mechanism of `urql`, as opposed to the opt-in
[Normalized Cache](../graphcache/normalized-caching.md).
+
- [**Errors**](../basics/errors.md) contains information on error handling in `urql`.
+5 -5
docs/basics/core.md
···
---
-
title: Core
order: 3
---
···
This concludes the introduction for using `@urql/core` without any framework bindings. This showed
just a couple of ways to use `gql` or the `Client`, however you may also want to learn more about
-
[how to use `urql`'s streams](../concepts/stream-patterns.md). Furthermore, apart from the framework
binding introductions, there are some other pages that provide more information on how to get fully
set up with `urql`:
-
- [How does the default "document cache" work?](../concepts/document-caching.md)
-
- [How are errors handled and represented?](../concepts/errors.md)
-
- [A quick overview of `urql`'s philosophy and structure.](../concepts/philosophy.md)
- [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)
···
---
+
title: Core Usage
order: 3
---
···
This concludes the introduction for using `@urql/core` without any framework bindings. This showed
just a couple of ways to use `gql` or the `Client`, however you may also want to learn more about
+
[how to use `urql`'s streams](../architecture.md#stream-patterns-in-urql). Furthermore, apart from the framework
binding introductions, there are some other pages that provide more information on how to get fully
set up with `urql`:
+
- [How does the default "document cache" work?](./document-caching.md)
+
- [How are errors handled and represented?](./errors.md)
+
- [A quick overview of `urql`'s architecture and structure.](../architecture.md)
- [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)
+7 -7
docs/basics/react-preact.md
···
---
-
title: React/Preact
order: 0
---
···
The result object contains several properties. The `fetching` field indicates whether we're currently
loading data, `data` contains the actual `data` from the API's result, and `error` is set when either
the request to the API has failed or when our API result contained some `GraphQLError`s, which
-
we'll get into later on the ["Errors" page](../concepts/errors.md).
### Variables
···
Request policies aren't specific to `urql`'s React API, but are a common feature in its core. [You
can learn more about how the cache behaves given the four different policies on the "Document
-
Caching" page.](../concepts/document-caching.md)
### Reexecuting Queries
···
If you're checking for errors, you should use `result.error` instead, which will be set
to a `CombinedError` when any kind of errors occurred while executing your mutation.
-
[Read more about errors on our "Errors" page.](../concepts/errors.md)
```jsx
const Todo = ({ id, title }) => {
···
which is the same between all framework bindings. Hence, next we may want to learn more about one of
the following to learn more about the internals:
-
- [How does the default "document cache" work?](../concepts/document-caching.md)
-
- [How are errors handled and represented?](../concepts/errors.md)
-
- [A quick overview of `urql`'s philosophy and structure.](../concepts/philosophy.md)
- [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)
···
---
+
title: React/Preact Bindings
order: 0
---
···
The result object contains several properties. The `fetching` field indicates whether we're currently
loading data, `data` contains the actual `data` from the API's result, and `error` is set when either
the request to the API has failed or when our API result contained some `GraphQLError`s, which
+
we'll get into later on the ["Errors" page](./errors.md).
### Variables
···
Request policies aren't specific to `urql`'s React API, but are a common feature in its core. [You
can learn more about how the cache behaves given the four different policies on the "Document
+
Caching" page.](../basics/document-caching.md)
### Reexecuting Queries
···
If you're checking for errors, you should use `result.error` instead, which will be set
to a `CombinedError` when any kind of errors occurred while executing your mutation.
+
[Read more about errors on our "Errors" page.](./errors.md)
```jsx
const Todo = ({ id, title }) => {
···
which is the same between all framework bindings. Hence, next we may want to learn more about one of
the following to learn more about the internals:
+
- [How does the default "document cache" work?](./document-caching.md)
+
- [How are errors handled and represented?](./errors.md)
+
- [A quick overview of `urql`'s architecture and structure.](../architecture.md)
- [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)
+6 -6
docs/basics/svelte.md
···
---
-
title: Svelte
order: 2
---
···
This "Getting Started" guide covers how to install and set up `urql` and provide a `Client` for
Svelte. The `@urql/svelte` package, which provides bindings for Svelte, doesn't fundamentally
function differently from `@urql/preact` or `urql` and uses the same [Core Package and
-
`Client`](../concepts/core-package.md).
### Installation
···
If you're checking for errors, you should use `operationStore.error` instead, which will be set
to a `CombinedError` when any kind of errors occurred while executing your mutation.
-
[Read more about errors on our "Errors" page.](../concepts/errors.md)
```jsx
mutateTodo({ id, title: newTitle }).then(result => {
···
which is the same between all framework bindings. Hence, next we may want to learn more about one of
the following to learn more about the internals:
-
- [How does the default "document cache" work?](../concepts/document-caching.md)
-
- [How are errors handled and represented?](../concepts/errors.md)
-
- [A quick overview of `urql`'s philosophy and structure.](../concepts/philosophy.md)
- [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)
···
---
+
title: Svelte Bindings
order: 2
---
···
This "Getting Started" guide covers how to install and set up `urql` and provide a `Client` for
Svelte. The `@urql/svelte` package, which provides bindings for Svelte, doesn't fundamentally
function differently from `@urql/preact` or `urql` and uses the same [Core Package and
+
`Client`](./core.md).
### Installation
···
If you're checking for errors, you should use `operationStore.error` instead, which will be set
to a `CombinedError` when any kind of errors occurred while executing your mutation.
+
[Read more about errors on our "Errors" page.](./errors.md)
```jsx
mutateTodo({ id, title: newTitle }).then(result => {
···
which is the same between all framework bindings. Hence, next we may want to learn more about one of
the following to learn more about the internals:
+
- [How does the default "document cache" work?](./document-caching.md)
+
- [How are errors handled and represented?](./errors.md)
+
- [A quick overview of `urql`'s architecture and structure.](../architecture.md)
- [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)
+6 -6
docs/basics/vue.md
···
---
-
title: Vue
order: 1
---
···
The result object contains several properties. The `fetching` field indicates whether we're currently
loading data, `data` contains the actual `data` from the API's result, and `error` is set when either
the request to the API has failed or when our API result contained some `GraphQLError`s, which
-
we'll get into later on the ["Errors" page](../concepts/errors.md).
All of these properties on the result are derived from the [shape of
`OperationResult`](../api/core.md#operationresult) and are marked as [reactive
···
If you're checking for errors, you should use `result.error` instead, which will be set
to a `CombinedError` when any kind of errors occurred while executing your mutation.
-
[Read more about errors on our "Errors" page.](../concepts/errors.md)
```js
import { useMutation } from '@urql/vue';
···
which is the same between all framework bindings. Hence, next we may want to learn more about one of
the following to learn more about the internals:
-
- [How does the default "document cache" work?](../concepts/document-caching.md)
-
- [How are errors handled and represented?](../concepts/errors.md)
-
- [A quick overview of `urql`'s philosophy and structure.](../concepts/philosophy.md)
- [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)
···
---
+
title: Vue Bindings
order: 1
---
···
The result object contains several properties. The `fetching` field indicates whether we're currently
loading data, `data` contains the actual `data` from the API's result, and `error` is set when either
the request to the API has failed or when our API result contained some `GraphQLError`s, which
+
we'll get into later on the ["Errors" page](./errors.md).
All of these properties on the result are derived from the [shape of
`OperationResult`](../api/core.md#operationresult) and are marked as [reactive
···
If you're checking for errors, you should use `result.error` instead, which will be set
to a `CombinedError` when any kind of errors occurred while executing your mutation.
+
[Read more about errors on our "Errors" page.](./errors.md)
```js
import { useMutation } from '@urql/vue';
···
which is the same between all framework bindings. Hence, next we may want to learn more about one of
the following to learn more about the internals:
+
- [How does the default "document cache" work?](./document-caching.md)
+
- [How are errors handled and represented?](./errors.md)
+
- [A quick overview of `urql`'s architecture and structure.](../architecture.md)
- [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)
-27
docs/concepts/README.md
···
-
---
-
title: Main Concepts
-
order: 3
-
---
-
-
# Main Concepts
-
-
In this chapter we'll learn about the motivation behind `urql`, the architecture that drives it, the
-
inner workings of the `Client`, and how to write extensions and addons, also known as _Exchanges_.
-
-
Each page goes a little further in explaining a core concept of `urql`.
-
-
- [**Document Caching**](./document-caching.md) explains the default cache mechanism of `urql`, as opposed to the opt-in
-
[Normalized Cache](../graphcache/normalized-caching.md).
-
- [**Errors**](./errors.md) contains information on error handling in `urql`.
-
- [**Philosophy**](./philosophy.md) gives a quick overview of the different aspects of GraphQL clients and `urql` in
-
particular, which shines a light on why you may want to use `urql`.
-
- [**Stream Pattern**](./stream-patterns.md) explains the inner working of `urql`, which is _stream-based_, also known as
-
Observable patterns in JS.
-
- [**Exchanges**](./exchanges.md) finally introduces _Exchanges_ and how to write extensions or addons and use them
-
in `urql`.
-
-
Finally, some _Exchanges_ are covered in different sections of the documentation, like
-
["Subscriptions"](../advanced/subscriptions.md), ["Server-side
-
Rendering"](../advanced/server-side-rendering.md), or ["Normalized
-
Caching"](../graphcache/normalized-caching.md). It's advisable to read this chapter before moving on
-
to using _Exchanges_.
···
+2 -2
docs/concepts/document-caching.md docs/basics/document-caching.md
···
---
title: Document Caching
-
order: 1
---
# Document Caching
···
a query and its variables.
The default _document caching_ logic is implemented in the default `cacheExchange`. We'll learn more
-
about ["Exchanges" on a later page.](../concepts/exchanges.md)
## Operation Keys
···
---
title: Document Caching
+
order: 4
---
# Document Caching
···
a query and its variables.
The default _document caching_ logic is implemented in the default `cacheExchange`. We'll learn more
+
about ["Exchanges" on the "Architecture" page.](../architecture.md)
## Operation Keys
+1 -1
docs/concepts/errors.md docs/basics/errors.md
···
---
title: Errors
-
order: 2
---
# Error handling
···
---
title: Errors
+
order: 5
---
# Error handling
+11 -32
docs/concepts/exchanges.md docs/advanced/authoring-exchanges.md
···
---
-
title: Exchanges
-
order: 5
---
-
# Exchanges
-
As we've learned on the [Stream Patterns](./stream-patterns.md) page, `urql`'s `Client` structures
its data as an event hub. We have an input stream of operations, which are instructions for the
`Client` to provide a result. These results then come from an output stream of operation results.
-
_Exchanges_ are responsible for performing the important transform from the operations (input) stream to the results stream. Exchanges are handler functions that deal with these input and
-
output streams. They're one of `urql`'s key components, and are needed to implement vital pieces of logic such as
-
caching, fetching, deduplicating requests, and more. In other words, Exchanges are handlers that
-
fulfill our GraphQL requests and can change the stream of operations or results.
-
The default set of exchanges that `@urql/core` contains and applies to a `Client` are:
-
-
- `dedupExchange`: Deduplicates pending operations (pending = waiting for a result)
-
- `cacheExchange`: The default caching logic with ["Document Caching"](../concepts/document-caching.md)
-
- `fetchExchange`: Sends an operation to the API using `fetch` and adds results to the output stream
-
-
Other available exchanges:
-
-
- [`errorExchange`](../api/core.md#errorexchange): Allows a global callback to be called when any error occurs
-
- [`ssrExchange`](../advanced/server-side-rendering.md): Allows for a server-side renderer to
-
collect results for client-side rehydration.
-
- [`retryExchange`](../api/retry-exchange.md): Allows operations to be retried
-
- [`multipartFetchExchange`](../api/multipart-fetch-exchange.md): Provides multipart file upload capability
-
- [`persistedFetchExchange`](../api/persisted-fetch-exchange.md): Provides support for Automatic
-
Persisted Queries
-
- [`authExchange`](../api/auth-exchange.md): Allows complex authentication flows to be implemented
-
easily.
-
- [`requestPolicyExchange`](../api/request-policy-exchange.md): Automatically upgrades `cache-only` and `cache-first` operations to `cache-and-network` after a given amount of time.
-
- [`refocusExchange`](../api/refocus-exchange.md): Tracks open queries and refetches them
-
when the window regains focus.
-
- `devtoolsExchange`: Provides the ability to use the [urql-devtools](https://github.com/FormidableLabs/urql-devtools)
-
-
It is also possible to apply custom exchanges to override the default logic.
## An Exchange Signature
···
[_Operations_](../api/core.md#operation) and returns a source of [_Operation
Results_](../api/core.md#operationresult).
-
- [Read more about streams on the "Stream Patterns" page.](../concepts/stream-patterns.md)
- [Read more about the _Exchange_ type signature on the API docs.](../api/core.md#exchange)
## Using Exchanges
···
---
+
title: Authoring Exchanges
+
order: 8
---
+
# Exchange Author Guide
+
As we've learned [on the "Architecture" page](../architecture.md) page, `urql`'s `Client` structures
its data as an event hub. We have an input stream of operations, which are instructions for the
`Client` to provide a result. These results then come from an output stream of operation results.
+
_Exchanges_ are responsible for performing the important transform from the operations (input) stream
+
to the results stream. Exchanges are handler functions that deal with these input and
+
output streams. They're one of `urql`'s key components, and are needed to implement vital pieces of
+
logic such as caching, fetching, deduplicating requests, and more. In other words, Exchanges are
+
handlers that fulfill our GraphQL requests and can change the stream of operations or results.
+
In this guide we'll learn more about how exchanges work and how we can write our own exchanges.
## An Exchange Signature
···
[_Operations_](../api/core.md#operation) and returns a source of [_Operation
Results_](../api/core.md#operationresult).
+
- [Read more about streams on the "Architecture" page.](../architecture.md#stream-patterns-in-urql)
- [Read more about the _Exchange_ type signature on the API docs.](../api/core.md#exchange)
## Using Exchanges
-111
docs/concepts/philosophy.md
···
-
---
-
title: Philosophy
-
order: 3
-
---
-
-
# Philosophy
-
-
`urql` is a highly customizable and flexible GraphQL client, that happens to come with some default
-
[core behavior in the core package](./core-package.md).
-
-
By default, we aim to provide features that allow you to build your app quickly with minimal
-
configuration. `urql` is designed to be a client that grows with you. As you go from building your first
-
GraphQL app to a utilising the full functionality, the tools are available to extend and customize `urql` based on
-
your needs.
-
-
In this guide, we will walk through how `urql` is set up internally and how all pieces of the puzzle
-
— the building blocks of `urql` — interact with one another.
-
-
## Hello World
-
-
When you use `urql` you will always create and set up a `Client`. There is a `createClient`
-
convenience helper to do just that.
-
-
```js
-
import { Client } from 'urql';
-
-
const client = new Client({
-
url: 'http://localhost:3000/graphql',
-
});
-
```
-
-
In `urql`, the client is the first step towards managing the complexity of GraphQL automatically.
-
-
## Using GraphQL Clients
-
-
You may have worked with a GraphQL API previously and noticed that using GraphQL in your app can be
-
as straightforward as sending a plain HTTP request with your query to fetch some data.
-
-
GraphQL also provides an opportunity to abstract away a lot of the manual work that goes with
-
sending these queries and managing the data. Ultimately, this lets you focus on building
-
your app without having to handle the technical details of state management in detail.
-
-
Specifically, `urql` simplifies three common aspects of using GraphQL:
-
-
- Sending queries and mutations and receiving results _declaratively_
-
- Abstracting _caching_ and state management internally
-
- Providing a central point of _extensibility_ and integration with your API
-
-
In the following sections we'll talk about how `urql` solves these three problems, and how this is
-
accomplished and abstracted internally.
-
-
## Declarative Queries
-
-
When you implement queries or mutations with `urql` the `Client` will internally manage the
-
lifetime and updates for these _operations_.
-
-
Such an _operation_ may be sent to your GraphQL API and you'll subsequently receive results.
-
When a _cache_ invalidates this result you may receive updated results. When your app
-
stops being interested in results for an _operation_ (e.g. React unmounts your component) then
-
the `Client` knows to _teardown_ the _operation_ and stops requesting new data or sending you
-
results.
-
-
![Operations and Results](../assets/urql-event-hub.png)
-
-
This all happens in the background, allowing you to simply declare that you'd like to have data for a given
-
query.
-
-
## Caching and State
-
-
When we use GraphQL queries and mutations declaratively with `urql`, we expect them to interact
-
and update automatically.
-
-
Furthermore, when we've already received the results from a query, we may not wish to send another request. To solve this, results can be cached in-memory and notifications can be sent to other parts of an app when the results change or
-
are invalidated by mutations/subscriptions.
-
-
GraphQL clients have access to some type information for any GraphQL API and hence can
-
cache the results of queries automatically. In `urql` the `Client` can be extended with several
-
cache implementations; all of them allow you to prevent mixing your declarative query or mutation
-
code with cache-implementation details, as they mostly happen behind the scenes.
-
-
We previously read about the default [Document Caching](../concepts/document-caching.md).
-
-
Some GraphQL clients also resort to caching data in a normalized format. This is similar to
-
[how you may store data in Redux.](https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape/)
-
Using this approach the cache uses more type information to reference parts of the GraphQL only once
-
in the cache and structures it in a graph, which leads to more shared data, and hence more shared
-
updates in your UI!
-
-
[Read more](../graphcache/normalized-caching.md) on how to add Normalized Caching to an app.
-
-
## Extensibility and Integration
-
-
With any kind of API there can be concerns outside of caching and state management. For example,
-
the global behavior or business logic of your application. For instance, you may want to add authentication, retry-logic for failed requests, or a global
-
error handler.
-
-
`urql` introduces the concept of _Exchanges_ in order to abstract the details of how the `Client` interacts with
-
your framework of choice, your app, and your GraphQL API. They are akin to
-
[middleware in Redux](https://redux.js.org/advanced/middleware) and have access to all operations
-
and all results.
-
-
Read more about [Exchanges](./exchanges.md) later on in the documentation.
-
-
All default behavior in the [core package](./core-package.md) is implemented using
-
Exchanges. This is possible as all operations and all results are treated as a stream
-
of events; we call these events "Operations".
-
-
![Operation Signature](../assets/urql-signals.png)
-
-
Thinking about GraphQL queries and results in
-
streams of operations and results allow us to implement complex behaviour in addition to allowing deep customisation over how the operations/results are handled. We'll learn more about this in the next section - [the Core Package](./core-package.md).
···
-120
docs/concepts/stream-patterns.md
···
-
---
-
title: Stream Patterns
-
order: 4
-
---
-
-
# Stream Patterns
-
-
As we've learned in the previous section on [philosophy](./philosophy.md), `urql`'s main way of handling GraphQL requests
-
is by abstracting them as streams of operations and results.
-
-
## Streams on the Client
-
-
The client abstracts GraphQL requests in a number of ways:
-
-
- as _Operations_
-
- descriptions of the GraphQL request
-
- the query and related variables
-
- additional information that is configured on the `Client`, such as
-
the `url` and `fetchOptions`.
-
-
![Operations stream and results stream](../assets/urql-client-architecture.png)
-
-
Internally the `Client` is an event hub. It defines a stream of operations as inputs, sends them
-
through a layer that will ultimately send GraphQL requests to an API, and then send the corresponding results
-
to another stream.
-
-
As a user working with framework code we never interact with these streams directly, but it's helpful to know that they describe
-
every interaction between the declarative queries we write and the way that `urql` fulfills them.
-
-
## Streams in JavaScript
-
-
Generally we refer to _streams_ as abstractions that allow us to program with asynchronous streams of
-
events over time. Within the JavaScript context we're thinking specifically in terms of of
-
[Observables](https://github.com/tc39/proposal-observable)
-
and [Reactive Programming with Observables.](http://reactivex.io/documentation/observable.html)
-
-
These concepts can be quite intimidating, if you're new to them, but from a high-level view what
-
we're talking about can be thought of as a "combination of Promises and Arrays".
-
Arrays because we're dealing with multiple items, and Promises because these items arrive
-
asynchronously.
-
-
Also most Observable libraries come with a toolkit of helper functions that are similar to the
-
methods on arrays, so you're likely to see `map` and `filter` — amongst other utilities — in those
-
libraries.
-
-
Read [this Gist](https://gist.github.com/staltz/868e7e9bc2a7b8c1f754) for a more in-depth
-
explanation.
-
-
## The Wonka library
-
-
`urql` utilises the [Wonka](https://github.com/kitten/wonka) library for its streams. It has a
-
few advantages that are specifically tailored for the `urql` library and ecosystem:
-
-
- It is extremely lightweight and treeshakeable, with a size of around 3.7kB minzipped.
-
- It's cross-platform and cross-language compatible, having been written in
-
[Reason](https://reasonml.github.io/) and provides support for [Flow](https://flow.org/)
-
and [TypeScript](https://www.typescriptlang.org/v2/).
-
- It's a predictable and iterable toolchain, emitting synchronous events whenever possible.
-
-
Typical usage of Wonka will involve creating a _source_ of some values and a _sink_.
-
-
```js
-
import { fromArray, map, subscribe, pipe } from 'wonka';
-
-
const { unsubscribe } = pipe(
-
fromArray([1, 2, 3]),
-
map(x => x * 2),
-
subscribe(x => {
-
console.log(x); // 2, 4, 6
-
})
-
);
-
```
-
-
In Wonka, like with Observables, streams are cancellable by calling the `unsubscribe` method that a
-
subscription returns.
-
-
Read more about Wonka in its [documentation](https://wonka.kitten.sh/basics/background).
-
-
## Client Query Streams
-
-
Internally the `Client` has methods that may be used to execute queries, mutations, and
-
subscriptions. These methods typically return `Wonka` streams that, when subscribed to, will
-
emit results for a given query.
-
-
When a result can be retrieved from an in-memory cache, the stream may even emit the result
-
synchronously — rather than asynchronously.
-
-
There are three methods for each type of operation that GraphQL supports;
-
`executeQuery`, `executeMutation`, and `executeSubscription`. All these methods are
-
convenience wrappers around `executeRequestOperation` that create an operation and return a stream.
-
-
There are also convenience wrappers around the "execute" methods that are useful when using `urql`
-
in a Node.js environment. They are the `query`, `mutation`, and `subscription` methods.
-
-
```js
-
import { pipe, subscribe } from 'wonka';
-
-
const QUERY = `
-
query Test($id: ID!) {
-
getUser(id: $id) {
-
id
-
name
-
}
-
}
-
`;
-
-
const { unsubscribe } = pipe(
-
client.query(QUERY, { id: 'test' }),
-
subscribe(result => {
-
console.log(result); // { data: ... }
-
})
-
);
-
```
-
-
All methods on the `Client` internally emit an operation on an "operations stream" and the result
-
for this operation will be filtered out of all results and delivered to your stream.
-
There are several of these convenience methods in `urql` that make it easier to work with the
-
concept of GraphQL operation and result streams.
-
-
Read more about the available APIs on the `Client` in the [Core API docs](../api/core.md).
···
+3 -3
docs/graphcache/README.md
···
# Graphcache
-
In `urql`, caching is fully configurable via [_Exchanges_](../concepts/exchanges.md) and the default
-
`cacheExchange` in `urql` offers a ["Document Cache"](../concepts/document-caching.md), which is
sufficient for sites that heavily rely and render static content. However as an app grows more
complex it's likely that the data and state that `urql` manages, will also grow more complex and
introduce interdependencies between data.
···
## Features
The following pages introduce different features in _Graphcache_ which together make it a compelling
-
alternative to the standard [document cache](../concepts/document-caching.md) that `urql` uses by
default.
- 🔁 [**Fully reactive, normalized caching.**](./normalized-caching.md) _Graphcache_ stores data in
···
# Graphcache
+
In `urql`, caching is fully configurable via [exchanges](../architecture.md) and the default
+
`cacheExchange` in `urql` offers a ["Document Cache"](../basics/document-caching.md), which is
sufficient for sites that heavily rely and render static content. However as an app grows more
complex it's likely that the data and state that `urql` manages, will also grow more complex and
introduce interdependencies between data.
···
## Features
The following pages introduce different features in _Graphcache_ which together make it a compelling
+
alternative to the standard [document cache](../basics/document-caching.md) that `urql` uses by
default.
- 🔁 [**Fully reactive, normalized caching.**](./normalized-caching.md) _Graphcache_ stores data in
+1 -1
docs/graphcache/offline.md
···
offline error — the `offlineExchange` won't deliver the error for this query to avoid it from being
surfaced to the user. This works particularly well in combination with ["Schema
Awareness"](./schema-awareness.md) which will deliver as much of a partial query result as possible.
-
In combination with the [`cache-and-network` request policy](../concepts/document-caching.md#request-policies)
we can now ensure that we display as much data as possible when the user is offline while still
keeping the cache up-to-date when the user is online.
···
offline error — the `offlineExchange` won't deliver the error for this query to avoid it from being
surfaced to the user. This works particularly well in combination with ["Schema
Awareness"](./schema-awareness.md) which will deliver as much of a partial query result as possible.
+
In combination with the [`cache-and-network` request policy](../basics/document-caching.md#request-policies)
we can now ensure that we display as much data as possible when the user is offline while still
keeping the cache up-to-date when the user is online.
+24 -4
packages/site/static.config.js
···
redirect: '/docs/basics',
},
{
-
path: '/docs/basics/document-caching',
-
redirect: '/docs/concepts/document-caching',
-
},
-
{
path: '404',
template: require.resolve('./src/screens/404'),
},
···
{
path: '/docs/graphcache/under-the-hood',
redirect: '/docs/graphcache/normalized-caching',
},
],
};
···
redirect: '/docs/basics',
},
{
path: '404',
template: require.resolve('./src/screens/404'),
},
···
{
path: '/docs/graphcache/under-the-hood',
redirect: '/docs/graphcache/normalized-caching',
+
},
+
{
+
path: '/docs/concepts/document-caching',
+
redirect: '/docs/basics/document-caching',
+
},
+
{
+
path: '/docs/concepts/errors',
+
redirect: '/docs/basics/errors',
+
},
+
{
+
path: '/docs/concepts',
+
redirect: '/docs/architecture',
+
},
+
{
+
path: '/docs/concepts/stream-patterns',
+
redirect: '/docs/architecture',
+
},
+
{
+
path: '/docs/concepts/philosophy',
+
redirect: '/docs/architecture',
+
},
+
{
+
path: '/docs/concepts/exchanges',
+
redirect: '/docs/advanced/authoring-exchanges',
},
],
};