Skip to content

Type-Safe version of fetch that uses OpenAPI TypeScript definitions to check API calls at compile type. This is really AWESOME if you call APIs from a JS frontend 🔥

License

Notifications You must be signed in to change notification settings

aurbano/typesafe-fetch

Repository files navigation

Better Alternatives

This repo works perfectly fine and is mostly just TS definitios that can be used to create typed fetch functions. However, there are better libraries that do a lot more than that:



Type-Safe Fetch

Given a path and a method, the TypeScript compiler will guarantee that you are passing the correct path and query parameters, and the correct body (and only if needed) + it will return the correct type for the response object!

Realised already how insanely awesome that is? The compiler will validate every aspect of the API request, including the response type - automatically!

Bonus: Tiny library (~1kb) with 0 dependencies.

Demo

Using typesafe-fetch with the Petstore demo API in VS Code to see the compiler suggested completions.

Screen capture

Usage

Install:

npm install typesafe-fetch

yarn add typesafe-fetch

Setup:

import getSafeFetch, { FetchFunction } from 'typesafe-fetch';

// See below how to generate the API definitions
import { paths as ApiDefinition } from "./petstore";

const fetchFn: FetchFunction = (url, { method, body, headers }) => {
  // You can also use a global error handler by catching errors here
  // Or insert any additional custom headers

  // This is also where you can decide which fetch function to use, see
  // below for examples using other libraries
  return fetch(url, { method, body, headers }).then(res => res.json());
};

// Now set up using your existing OpenAPI definition
const safeFetch = getSafeFetch<ApiDefinition>({
  fetch: fetchFn,
});

// Make API calls :)
const res = safeFetch('/endpoint', {
  query: {
    sampleParam: 123,
  },
});

Using with multiple APIs

You can use union types to combine multiple APIs into one (assuming the endpoints are different and the base URL is the same, otherwise just use different instances of safeFetch)

import { paths as SomeApiDefinition } from "./some-api";
import { paths as SomeOtherApiDefinition } from "./some-other-api";

const safeFetch = getSafeFetch<SomeApiDefinition & SomeOtherApiDefinition>({
  fetch,
});

Generating the API definitions

This library relies on the TS models generated by OpenAPI-TypeScript

For the simplest way to generate the models run:

npx openapi-typescript https://petstore.swagger.io/v2/swagger.json --output petstore.schema.ts

Check out their docs for more advanced use-cases.

Fetch function

The library is setup by calling getSafeFetch<ApiDefinition>() with your ApiDefinition and an object containing an optional baseUrl and a mandatory fetch function.

This function has the following signature:

type FetchOptions = {
  method: string;
  body?: BodyInit;
  headers?: HeadersInit;
}

export type FetchFunction = (url: string, options: FetchOptions) => Promise<any>;

All you need is to pass a function that will send the request in any way, and return a Promise with the return data (not a Response object, you must extract it from there).

Using fetch as a fetch function

You can either use the browser's built-in fetch function, or any of the polyfills such as node-fetch, cross-fetch...

const fetchFn: FetchFunction = (url, { method, body, headers }) => 
  fetch(url, { method, body, headers }).then(res => res.json());

Using axios as a fetch function

You can either use the browser's built-in fetch function, or any of the polyfills such as node-fetch, cross-fetch...

const fetchFn: FetchFunction = (url, { method, body, headers }) => 
  axios({
    url,
    method,
    headers,
    data: body,
  }).then(res => res.data);

About

Type-Safe version of fetch that uses OpenAPI TypeScript definitions to check API calls at compile type. This is really AWESOME if you call APIs from a JS frontend 🔥

Resources

License

Stars

Watchers

Forks

Packages

No packages published