Git Product home page Git Product logo

openapi-fetch's Introduction

🎾 openapi-fetch

Ultra-fast fetching for TypeScript generated automatically from your OpenAPI schema. Weighs in at 1 kb and has virtually zero runtime. Works with React, Vue, Svelte, or vanilla JS.

Library Size (min)
openapi-fetch 1 kB
openapi-typescript-fetch 4 kB
openapi-typescript-codegen 345 kB*

* Note: codegen depends on the scope of your API: the larger it is, the larger your client weight. This is the actual weight of GitHub’s REST API client.

The syntax is inspired by popular libraries like react-query or Apollo client, but without all the bells and whistles and in a 1 kb package.

import createClient from 'openapi-fetch';
import { paths } from './v1'; // (generated from openapi-typescript)

const { get, post } = createClient<paths>();

// Type-checked request

await post('/create-post', {
  body: {
    title: 'My New Post',
    // ❌ Property 'publish_date' is missing in type …
  },
});

// Type-checked response

const { data, error } = await get('/post/my-blog-post');

console.log(data.title); // ❌ 'data' is possibly 'undefined'
console.log(error.message); // ❌ 'error' is possibly 'undefined'
console.log(data?.foo); // ❌ Property 'foo' does not exist on type …

Notice there are no generics, and no manual typing. Your endpoint’s exact request & response was inferred automatically off the URL. This makes a big difference in the type safety of your endpoints! This eliminates all of the following:

  • βœ… No malformed URLs
  • βœ… Always using the correct method
  • βœ… All parameters are fully type-checked and matched the schema
  • βœ… For POST and PATCH, etc., all request bodies are fully type-checked as well
  • βœ… No chance the wrong type was manually imported
  • βœ… No chance typing was bypassed altogether
  • βœ… All of this in a 1 kB client package πŸŽ‰

πŸ”§ Setup

First install this package and openapi-typescript from npm:

npm i -D openapi-fetch openapi-typescript

Next, generate TypeScript types from your OpenAPI schema using openapi-typescript:

npx openapi-typescript ./path/to/api/v1.yaml -o ./src/lib/api/v1.d.ts

Note: be sure to validate your schema first! openapi-typescript will err on invalid schemas.

Lastly, create the client while configuring default options:

import createClient from 'openapi-fetch';
import { paths } from './v1'; // (generated from openapi-typescript)

const { get, post, put, patch, del } = createClient<paths>({
  baseUrl: 'https://myserver.com/api/v1/',
  headers: {
    Authorization: `Bearer ${import.meta.env.VITE_AUTH_TOKEN}`,
  },
});

πŸ“ Usage

Using openapi-fetch is as easy as reading your schema! For example, given the following schema:

# v1.yaml
paths:
  /post/{post_id}:
    get:
      parameters:
        - in: path
          name: post_id
          required: true
        - in: query
          name: version
      responses:
        200: #…
        404: #…
  /create-post:
    post:
      requestBody:
        required: true
        schema:
          content:
            application/json:
              type: object
              properties:
                title:
                  type: string
                body:
                  type: string
                publish_date:
                  type: number
              required:
                - title
                - body
                - publish_date
      responses:
        200: #…
        500: #…

Here’s how you’d query either endpoint:

import createClient from 'openapi-fetch';
import { paths } from './v1';

const { get, post } = createClient<paths>();

// GET /post/{post_id}
const { data, error } = await get('/post/{post_id}', {
  params: {
    path: { post_id: 'my-post' },
    query: { version: 2 },
  },
});

// POST /create-post
const { data, error } = await post('/create-post', {
  body: {
    title: 'New Post',
    body: '<p>New post body</p>',
    publish_date: new Date('2023-03-01T12:00:00Z').getTime(),
  },
});

Note in the get() example, the URL was actually /post/{post_id}, not /post/my-post. The URL matched the OpenAPI schema definition rather than the final URL. This library will replace the path param correctly for you, automatically.

πŸ”’ Handling Auth

Authentication often requires some reactivity dependent on a token. Since this library is so low-level, there are myriad ways to handle it:

Nano Stores

Here’s how it can be handled using nanostores, a tiny (334 b), universal signals store:

// src/lib/api/index.ts
import { atom, computed } from 'nanostores';
import createClient from 'openapi-fetch';
import { paths } from './v1';

export const authToken = atom<string | undefined>();
someAuthMethod().then((newToken) => authToken.set(newToken));

export const client = computed(authToken, (currentToken) =>
  createClient<paths>({
    headers: currentToken ? { Authorization: `Bearer ${currentToken}` } : {},
  })
);

// src/some-other-file.ts
import { client } from './lib/api';

const { get, post } = client.get();

get('/some-authenticated-url', {
  /* … */
});

Vanilla JS Proxies

You can also use proxies which are now supported in all modern browsers:

// src/lib/api/index.ts
import createClient from 'openapi-fetch';
import { paths } from './v1';

let authToken: string | undefined = undefined;
someAuthMethod().then((newToken) => (authToken = newToken));

const baseClient = createClient<paths>();
export default new Proxy(baseClient, {
  get(_, key: keyof typeof baseClient) {
    const newClient = createClient<paths>({ headers: authToken ? { Authorization: `Bearer ${authToken}` } : {} });
    return newClient[key];
  },
});

// src/some-other-file.ts
import client from './lib/api';

client.get('/some-authenticated-url', {
  /* … */
});

πŸŽ›οΈ Config

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

Name Type Description
baseUrl string Prefix all fetch URLs with this option.

In addition, you may pass any other fetch options such as headers, mode, credentials, redirect, etc. (docs).

🎯 Project Goals

  1. Infer types automatically from OpenAPI schemas without generics (or, only the absolute minimum needed)
  2. Respect the native fetch() API while reducing boilerplate (such as await res.json())
  3. Be as small and light as possible

πŸ§™β€β™€οΈ Advanced

Caching

By default, this library does NO caching of any kind (it’s 1 kb, remember?). However, this library can be easily wrapped using any method of your choice, while still providing strong typechecking for endpoints.

Differences from openapi-typescript-fetch

This library is identical in purpose to openapi-typescript-fetch, but has the following differences:

  • This library has a built-in error type for 3xx/4xx/5xx errors whereas openapi-typescript-fetch throws exceptions (requiring you to wrap things in try/catch)
  • This library has a more terse syntax (get(…)) wheras openapi-typescript-fetch requires chaining (.path(…).method(…).create())
  • openapi-typescript-fetch supports middleware whereas this library doesn’t

openapi-fetch's People

Contributors

drwpow avatar fergusean avatar fletchertyler914 avatar mitchell-merry avatar nholik avatar shinzui avatar

Stargazers

 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.