Skip to content

Latest commit

 

History

History
521 lines (376 loc) · 25.4 KB

core.md

File metadata and controls

521 lines (376 loc) · 25.4 KB
title order
@urql/core
0

@urql/core

Note: These API docs are deprecated as we now keep TSDocs in all published packages. You can view TSDocs while using these packages in your editor, as long as it supports the TypeScript Language Server. We're planning to replace these API docs with a separate web app soon.

The @urql/core package is the basis of all framework bindings. Each bindings-package, like urql for React or @urql/preact, will reuse the core logic and reexport all exports from @urql/core. 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.

Client

The Client manages all operations and ongoing requests to the exchange pipeline. It accepts several options on creation.

@urql/core also exposes createClient() that is just a convenient alternative to calling new Client().

Input Type Description
exchanges Exchange[] An array of Exchanges that the client should use
url string The GraphQL API URL as used by fetchExchange
fetchOptions RequestInit | () => RequestInit Additional fetchOptions that fetch in fetchExchange should use to make a request
fetch typeof fetch An alternative implementation of fetch that will be used by the fetchExchange instead of window.fetch
suspense ?boolean Activates the experimental React suspense mode, which can be used during server-side rendering to prefetch data
requestPolicy ?RequestPolicy Changes the default request policy that will be used. By default, this will be cache-first.
preferGetMethod ?boolean | 'force' | 'within-url-limit' This is picked up by the fetchExchange and will force all queries (not mutations) to be sent using the HTTP GET method instead of POST if the length of the resulting URL doesn't exceed 2048 characters. When 'force' is passed a GET request is always sent regardless of how long the resulting URL is.

client.executeQuery

Accepts a GraphQLRequest and optionally Partial<OperationContext>, and returns a Source<OperationResult> — a stream of query results that can be subscribed to.

Internally, subscribing to the returned source will create an Operation, with kind set to 'query', and dispatch it on the exchanges pipeline. If no subscribers are listening to this operation anymore and unsubscribe from the query sources, the Client will dispatch a "teardown" operation.

client.executeSubscription

This is functionally the same as client.executeQuery, but creates operations for subscriptions instead, with kind set to 'subscription'.

client.executeMutation

This is functionally the same as client.executeQuery, but creates operations for mutations instead, with kind set to 'mutation'.

A mutation source is always guaranteed to only respond with a single OperationResult and then complete.

client.query

This is a shorthand method for client.executeQuery, which accepts a query (DocumentNode | string) and variables separately and creates a GraphQLRequest createRequest automatically.

The returned Source<OperationResult> will also have an added toPromise method, so the stream can be conveniently converted to a promise.

import { pipe, subscribe } from 'wonka';

const { unsubscribe } = pipe(
  client.query('{ test }', {
    /* vars */
  }),
  subscribe(result => {
    console.log(result); // OperationResult
  })
);

// or with toPromise, which also limits this to one result
client
  .query('{ test }', {
    /* vars */
  })
  .toPromise()
  .then(result => {
    console.log(result); // OperationResult
  });

Read more about how to use this API on the "Core Package" page.

client.mutation

This is similar to client.query, but dispatches mutations instead.

Read more about how to use this API on the "Core Package" page.

client.subscription

This is similar to client.query, but does not provide a toPromise() helper method on the streams it returns.

Read more about how to use this API on the "Subscriptions" page.

client.reexecuteOperation

This method is commonly used in Exchanges to reexecute an Operation on the Client. It will only reexecute when there are still subscribers for the given Operation.

For an example, this method is used by the cacheExchange when an OperationResult is invalidated in the cache and needs to be refetched.

client.readQuery

This method is typically used to read data synchronously from a cache. It returns an OperationResult if a value is returned immediately or null if no value is returned while cancelling all side effects.

CombinedError

The CombinedError is used in urql to normalize network errors and GraphQLErrors if anything goes wrong during a GraphQL request.

Input Type Description
networkError ?Error An unexpected error that might've occurred when trying to send the GraphQL request
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.

Types

GraphQLRequest

This often comes up as the input for every GraphQL request. It consists of query and optionally variables.

Prop Type Description
key number A unique key that identifies this exact combination of query and variables, which is derived using a stable hash.
query DocumentNode The query to be executed. Accepts as a plain string query or GraphQL DocumentNode.
variables ?object The variables to be used with the GraphQL request.

The key property is a hash of both the query and the variables, to uniquely identify the request. When variables are passed it is ensured that they're stably stringified so that the same variables in a different order will result in the same key, since variables are order-independent in GraphQL.

A GraphQLRequest may be manually created using the createRequest helper.

OperationType

This determines what kind of operation the exchanges need to perform. This is one of:

  • 'subscription'
  • 'query'
  • 'mutation'
  • 'teardown'

The 'teardown' operation is special in that it instructs exchanges to cancel any ongoing operations with the same key as the 'teardown' operation that is received.

Operation

The input for every exchange that informs GraphQL requests. It extends the GraphQLRequest type and contains these additional properties:

Prop Type Description
kind OperationType The type of GraphQL operation being executed.
context OperationContext Additional metadata passed to exchange.

An Operation also contains the operationName property, which is a deprecated alias of the kind property and outputs a deprecation warning if it's used.

RequestPolicy

This determines the strategy that a cache exchange should use to fulfill an operation. When you implement a custom cache exchange it's recommended that these policies are handled.

  • 'cache-first' (default)
  • 'cache-only'
  • 'network-only'
  • 'cache-and-network'

Read more about request policies on the "Document Caching" page.

OperationContext

The context often carries options or metadata for individual exchanges, but may also contain custom data that can be passed from almost all API methods in urql that deal with Operations.

Some of these options are set when the Client is initialised, so in the following list of properties you'll likely see some options that exist on the Client as well.

Prop Type Description
fetchOptions ?RequestInit | (() => RequestInit) Additional fetchOptions that fetch in fetchExchange should use to make a request.
fetch typeof fetch An alternative implementation of fetch that will be used by the fetchExchange instead of window.fetch
requestPolicy RequestPolicy An optional request policy that should be used specifying the cache strategy.
url string The GraphQL endpoint, when using GET you should use absolute url's
meta ?OperationDebugMeta Metadata that is only available in development for devtools.
suspense ?boolean Whether suspense is enabled.
preferGetMethod ?boolean | 'force' | 'within-url-limit' Instructs the fetchExchange to use HTTP GET for queries.
additionalTypenames ?string[] Allows you to tell the operation that it depends on certain typenames (used in document-cache.)

It also accepts additional, untyped parameters that can be used to send more information to custom exchanges.

OperationResult

The result of every GraphQL request, i.e. an Operation. It's very similar to what comes back from a typical GraphQL API, but slightly enriched and normalized.

Prop Type Description
operation Operation The operation that this is a result for
data ?any Data returned by the specified query
error ?CombinedError A CombinedError instances that wraps network or GraphQLErrors (if any)
extensions ?Record<string, any> Extensions that the GraphQL server may have returned.
stale ?boolean A flag that may be set to true by exchanges to indicate that the data is incomplete or out-of-date, and that the result will be updated soon.

ExchangeInput

This is the input that an Exchange receives when it's initialized by the Client

Input Type Description
forward ExchangeIO The unction responsible for receiving an observable operation and returning a result
client Client The urql application-wide client library. Each execute method starts a GraphQL request and returns a stream of results.

Exchange

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.

An exchange is defined to be a function that receives ExchangeInput and returns an ExchangeIO function. The ExchangeIO function in turn will receive a stream of operations, and must return a stream of results. If the exchange is purely transforming data, like the mapExchange for instance, it'll call forward, which is the next Exchange's ExchangeIO function to get a stream of results.

type ExchangeIO = (Source<Operation>) => Source<OperationResult>;
type Exchange = ExchangeInput => ExchangeIO;

If you haven't yet seen streams you can read more about "Stream Patterns" on the "Architecture" page.

Exchanges

cacheExchange

The cacheExchange as described on the "Document Caching" page.. It's of type Exchange.

subscriptionExchange

The subscriptionExchange as described on the "Subscriptions" page.. It's of type Options => Exchange.

It accepts a single input: { forwardSubscription }. This is a function that receives an enriched operation and must return an Observable-like object that streams GraphQLResults with data and errors.

The forwardSubscription function is commonly connected to the subscriptions-transport-ws package.

ssrExchange

The ssrExchange as described on the "Server-side Rendering" page.. It's of type Options => Exchange.

It accepts three inputs, initialState which is completely optional and populates the server-side rendered data with a rehydrated cache, isClient which can be set to true or false to tell the ssrExchange whether to write to (server-side) or read from (client-side) the cache, and staleWhileRevalidate which will treat rehydrated data as stale and refetch up-to-date data by reexecuring the operation using a network-only requests policy.

By default, isClient defaults to true when the Client.suspense mode is disabled and to false when the Client.suspense mode is enabled.

This can be used to extract data that has been queried on the server-side, which is also described in the Basics section, and is also used on the client-side to restore server-side rendered data.

When called, this function creates an Exchange, which also has two methods on it:

  • .restoreData(data) which can be used to inject data, typically on the client-side.
  • .extractData() which is typically used on the server-side to extract the server-side rendered data.

Basically, the ssrExchange is a small cache that collects data during the server-side rendering pass, and allows you to populate the cache on the client-side with the same data.

During React rehydration this cache will be emptied, and it will become inactive and won't change the results of queries after rehydration.

It needs to be used after other caching Exchanges like the cacheExchange, but before any asynchronous Exchange like the fetchExchange.

debugExchange

An exchange that writes incoming Operations to console.log and writes completed OperationResults to console.log.

This exchange is disabled in production and is based on the mapExchange. If you'd like to customise it, you can replace it with a custom mapExchange.

fetchExchange

The fetchExchange of type Exchange is responsible for sending operations of type 'query' and 'mutation' to a GraphQL API using fetch.

mapExchange

The mapExchange allows you to:

  • react to or replace operations with onOperation,
  • react to or replace results with onResult,
  • and; react to errors in results with onError.

It can therefore be used to quickly react to the core events in the Client without writing a custom exchange, effectively allowing you to ship your own debugExchange.

mapExchange({
  onOperation(operation) {
    console.log('operation', operation);
  },
  onResult(result) {
    console.log('result', result);
  },
});

It can also be used to react only to errors, which is the same as checking for result.error:

mapExchange({
  onError(error, operation) {
    console.log(`The operation ${operation.key} has errored with:`, error);
  },
});

Lastly, it can be used to map operations and results, which may be useful to update the OperationContext or perform other standard tasks that require you to wait for a result:

import { mapExchange, makeOperation } from '@urql/core';

mapExchange({
  async onOperation(operation) {
    // NOTE: This is only for illustration purposes
    return makeOperation(operation.kind, operation, {
      ...operation.context,
      test: true,
    });
  },
  async onResult(result) {
    // NOTE: This is only for illustration purposes
    if (result.data === undefined) result.data = null;
    return result;
  },
});

errorExchange (deprecated)

An exchange that lets you inspect errors. This can be useful for logging, or reacting to different types of errors (e.g. logging the user out in case of a permission error).

In newer versions of @urql/core, it's identical to the mapExchange and its export has been replaced as the mapExchange also allows you to pass an onError function.

Utilities

gql

This is a gql tagged template literal function, similar to the one that's also commonly known from graphql-tag. It can be used to write GraphQL documents in a tagged template literal and returns a parsed DocumentNode that's primed against the createRequest's cache for keys.

import { gql } from '@urql/core';

const SharedFragment = gql`
  fragment UserFrag on User {
    id
    name
  }
`;

gql`
  query {
    user
    ...UserFrag
  }

  ${SharedFragment}
`;

Unlike graphql-tag, this function outputs a warning in development when names of fragments in the document are duplicated. It does not output warnings when fragment names were duplicated globally however.

stringifyVariables

This function is a variation of JSON.stringify that sorts any object's keys that is being stringified to ensure that two objects with a different order of keys will be stably stringified to the same string.

stringifyVariables({ a: 1, b: 2 }); // {"a":1,"b":2}
stringifyVariables({ b: 2, a: 1 }); // {"a":1,"b":2}

createRequest

This utility accepts a GraphQL query of type string | DocumentNode and optionally an object of variables, and returns a GraphQLRequest object.

Since the client.executeQuery and other execute methods only accept GraphQLRequests, this helper is commonly used to create that request first. The client.query and client.mutation methods use this helper as well to create requests.

The helper takes care of creating a unique key for the GraphQLRequest. This is a hash of the query and variables if they're passed. The variables will be stringified using stringifyVariables, which outputs a stable JSON string.

Additionally, this utility will ensure that the query reference will remain stable. This means that if the same query will be passed in as a string or as a fresh DocumentNode, then the output will always have the same DocumentNode reference.

makeOperation

This utility is used to either turn a GraphQLRequest object into a new Operation object or to copy an Operation. It adds the kind property, and the operationName alias that outputs a deprecation warning.

It accepts three arguments:

Hence some valid uses of the utility are:

// Create a new operation from scratch
makeOperation('query', createRequest(query, variables), client.createOperationContext(opts));

// Turn an operation into a 'teardown' operation
makeOperation('teardown', operation);

// Copy an existing operation while modifying its context
makeOperation(operation.kind, operation, {
  ...operation.context,
  preferGetMethod: true,
});

makeResult

This is a helper function that converts a GraphQL API result to an OperationResult.

It accepts an Operation, the API result, and optionally the original FetchResponse for debugging as arguments, in that order.

makeErrorResult

This is a helper function that creates an OperationResult for GraphQL API requests that failed with a generic or network error.

It accepts an Operation, the error, and optionally the original FetchResponse for debugging as arguments, in that order.

formatDocument

This utility is used by the cacheExchange and by Graphcache to add __typename fields to GraphQL DocumentNodes.

composeExchanges

This utility accepts an array of Exchanges and composes them into a single one. It chains them in the order that they're given, left to right.

function composeExchanges(Exchange[]): Exchange;

This can be used to combine some exchanges and is also used by Client to handle the exchanges input.