Skip to content

Latest commit

 

History

History
291 lines (215 loc) · 16 KB

File metadata and controls

291 lines (215 loc) · 16 KB
title description
API
openapi-fetch API

API

createClient

createClient accepts the following options, which set the default settings for all subsequent fetch calls.

createClient<paths>(options);
Name Type Description
baseUrl string Prefix all fetch URLs with this option (e.g. "https://myapi.dev/v1/")
fetch fetch Fetch instance used for requests (default: globalThis.fetch)
querySerializer QuerySerializer (optional) Provide a querySerializer
bodySerializer BodySerializer (optional) Provide a bodySerializer
(Fetch options) Any valid fetch option (headers, mode, cache, signal …) (docs

Fetch options

The following options apply to all request methods (.GET(), .POST(), etc.)

client.GET("/my-url", options);
Name Type Description
params ParamsObject path and query params for the endpoint
body { [name]:value } requestBody data for the endpoint
querySerializer QuerySerializer (optional) Provide a querySerializer
bodySerializer BodySerializer (optional) Provide a bodySerializer
parseAs "json" | "text" | "arrayBuffer" | "blob" | "stream" (optional) Parse the response using a built-in instance method (default: "json"). "stream" skips parsing altogether and returns the raw stream.
baseUrl string Prefix the fetch URL with this option (e.g. "https://myapi.dev/v1/")
fetch fetch Fetch instance used for requests (default: fetch from createClient)
middleware Middleware[] See docs
(Fetch options) Any valid fetch option (headers, mode, cache, signal, …) (docs)

wrapAsPathBasedClient

wrapAsPathBasedClient wraps the result of createClient() to return a Proxy-based client that allows path-indexed calls:

const client = createClient<paths>(clientOptions);
const pathBasedClient = wrapAsPathBasedClient(client);

pathBasedClient["/my-url"].GET(fetchOptions);

The fetchOptions are the same than for the base client.

A path based client can lead to better type inference but comes at a runtime cost due to the use of a Proxy.

createPathBasedClient is a convenience method combining createClient and wrapAsPathBasedClient if you only want to use the path based call style:

const client = createPathBasedClient<paths>(clientOptions);

client["/my-url"].GET(fetchOptions);

Note that it does not allow you to attach middlewares. If you need middlewares, you need to use the full form:

const client = createClient<paths>(clientOptions);

client.use(...);

const pathBasedClient = wrapAsPathBasedClient(client);

client.use(...); // the client reference is shared, so the middlewares will propagate.

pathBasedClient["/my-url"].GET(fetchOptions);

querySerializer

OpenAPI supports different ways of serializing objects and arrays for parameters (strings, numbers, and booleans—primitives—always behave the same way). By default, this library serializes arrays using style: "form", explode: true, and objects using style: "deepObject", explode: true, but you can customize that behavior with the querySerializer option (either on createClient() to control every request, or on individual requests for just one).

Object syntax

openapi-fetch ships the common serialization methods out-of-the-box:

Option Type Description
array SerializerOptions Set style and explode for arrays (docs). Default: { style: "form", explode: true }.
object SerializerOptions Set style and explode for objects (docs). Default: { style: "deepObject", explode: true }.
allowReserved boolean Set to true to skip URL encoding (⚠️ may break the request) (docs). Default: false.
const client = createClient({
  querySerializer: {
    array: {
      style: "pipeDelimited", // "form" (default) | "spaceDelimited" | "pipeDelimited"
      explode: true,
    },
    object: {
      style: "form", // "form" | "deepObject" (default)
      explode: true,
    },
  },
});

Array styles

Style Array id = [3, 4, 5]
form /users?id=3,4,5
form (exploded, default) /users?id=3&id=4&id=5
spaceDelimited /users?id=3%204%205
spaceDelimited (exploded) /users?id=3&id=4&id=5
pipeDelimited /users?id=3|4|5
pipeDelimited (exploded) /users?id=3&id=4&id=5

Object styles

Style Object id = {"role": "admin", "firstName": "Alex"}
form /users?id=role,admin,firstName,Alex
form (exploded) /users?role=admin&firstName=Alex
deepObject (default) /users?id[role]=admin&id[firstName]=Alex

::: tip

deepObject is always exploded, so it doesn’t matter if you set explode: true or explode: false—it’ll generate the same output.

:::

Alternate function syntax

Sometimes your backend doesn’t use one of the standard serialization methods, in which case you can pass a function to querySerializer to serialize the entire string yourself. You’ll also need to use this if you’re handling deeply-nested objects and arrays in your params:

const client = createClient({
  querySerializer(queryParams) {
    const search = [];
    for (const name in queryParams) {
      const value = queryParams[name];
      if (Array.isArray(value)) {
        for (const item of value) {
          s.push(`${name}[]=${encodeURIComponent(item)}`);
        }
      } else {
        s.push(`${name}=${encodeURLComponent(value)}`);
      }
    }
    return search.join(","); // ?tags[]=food,tags[]=california,tags[]=healthy
  },
});

::: warning

When serializing yourself, the string will be kept exactly as-authored, so you’ll have to call encodeURI or encodeURIComponent to escape special characters.

:::

bodySerializer

Similar to querySerializer, bodySerializer allows you to customize how the requestBody is serialized if you don’t want the default JSON.stringify() behavior. You probably only need this when using multipart/form-data:

const { data, error } = await client.PUT("/submit", {
  body: {
    name: "",
    query: { version: 2 },
  },
  bodySerializer(body) {
    const fd = new FormData();
    for (const name in body) {
      fd.append(name, body[name]);
    }
    return fd;
  },
});

::: tip

For convenience, openapi-fetch sets Content-Type to application/json automatically for any request that provides value for the body parameter. When the bodySerializer returns an instance of FormData, Content-Type is omitted, allowing the browser to set it automatically with the correct message part boundary.

You can also set Content-Type manually through headers object either in the fetch options, or when instantiating the client.

:::

Path serialization

openapi-fetch supports path serialization as outlined in the 3.1 spec. This happens automatically, based on the specific format in your OpenAPI schema:

Template Style Primitive id = 5 Array id = [3, 4, 5] Object id = {"role": "admin", "firstName": "Alex"}
/users/{id} simple (default) /users/5 /users/3,4,5 /users/role,admin,firstName,Alex
/users/{id*} simple (exploded) /users/5 /users/3,4,5 /users/role=admin,firstName=Alex
/users/{.id} label /users/.5 /users/.3,4,5 /users/.role,admin,firstName,Alex
/users/{.id*} label (exploded) /users/.5 /users/.3.4.5 /users/.role=admin.firstName=Alex
/users/{;id} matrix /users/;id=5 /users/;id=3,4,5 /users/;id=role,admin,firstName,Alex
/users/{;id*} matrix (exploded) /users/;id=5 /users/;id=3;id=4;id=5 /users/;role=admin;firstName=Alex

Middleware

Middleware is an object with onRequest(), onResponse() and onError() callbacks that can observe and modify requests, responses and errors.

import createClient from "openapi-fetch";
import type { paths } from "./my-openapi-3-schema"; // generated by openapi-typescript

const myMiddleware: Middleware = {
  async onRequest({ request, options }) {
    // set "foo" header
    request.headers.set("foo", "bar");
    return request;
  },
  async onResponse({ request, response, options }) {
    const { body, ...resOptions } = res;
    // change status of response
    return new Response(body, { ...resOptions, status: 200 });
  },
  async onError({ error }) {
    // wrap errors thrown by fetch
    onError({ error }) {
      return new Error("Oops, fetch failed", { cause: error });
    },
  },
};

const client = createClient<paths>({ baseUrl: "https://myapi.dev/v1/" });

// register middleware
client.use(myMiddleware);

API

Parameters

Each middleware callback receives the following options object with the following:

Name Type Description
request Request The current Request to be sent to the endpoint.
schemaPath string The original OpenAPI path called (e.g. /users/{user_id})
params Object The original params object passed to GET() / POST() / etc.
id string A random, unique ID for this request.
options ClientOptions The readonly options passed to createClient().

In addition to these, the onResponse callback receives an additional response property:

Name Type Description
response Response The Response returned from the endpoint.

And the onError callback receives an additional error property:

Name Type Description
error unknown The error thrown by fetch, probably a TypeError or a DOMException.

Response

Each middleware callback can return:

  • onRequest: A Request to modify the request, a Response to short-circuit the middleware chain, or undefined to leave request untouched (skip)
  • onResponse: Either a Response to modify the response, or undefined to leave it untouched (skip)
  • onError: Either an Error to modify the error that is thrown, a Response which means that the fetch call will proceed as successful, or undefined to leave the error untouched (skip)

Ejecting middleware

To remove middleware, call client.eject(middleware):

const myMiddleware = {
  // …
};

// register middleware
client.use(myMiddleware);

// remove middleware
client.eject(myMiddleware);

For additional guides & examples, see Middleware & Auth