Client

Overview

npm i @webroute/client

The @webroute/client package provides a simple and flexible abstraction for interacting with any REST API type-safely.

It works with any fetching library of your choice and is designed to expedite client-side development as well as reducing errors and mistakes, by better enforcing your API contract.


Define App

We can arbitrarily define our API schema for a typed client via the DefineApp type.

import { DefineApp } from "@webroute/client";
 
type App = DefineApp<{
  "GET /posts": {
    Query: { limit?: number };
  };
}>;

Typed Client

The typed client is an extremely lightweight, so-called "headless" client-side interface for your API. It is entirely unopinionated about how fetching is done and merely wires up end-to-end type safety, without getting in your way.

react-app/api-client.ts
// Create a lightweight client instance
const  = <>()({
  : async (, : { : string }) => {
    return { : "123" };
  },
});
 
// Each API operation is represented as a single, flat key
// in the form `{METHOD} {path}`
const  = ("GET /posts");
 
const  = ({ : { : 12 } }, { : "bar" });

Our custom fetcher is responsible for executing our request and parsing our response, if need be. It allows for flexible options and return types.

import { createUrl } from "@webroute/client";
 
const myFetcher = async (
  // Contains info about path, method, body etc.
  config,
 
  // Any additional parameters are exposed via the client instance
  // and fully typed.
  opts: AxiosRequestConfig
) => {
  const { path, method, body, params, query } = config;
 
  // ... Fetch using any method...
};

Schema Types

The App definition is a very simple type which we can directly reference to get information on our routes body, output etc.

const operation = "GET /posts" satistfies keyof App // an API operation
type Endpoint = App[typeof operation];
 
type Query = Endpoint["Query"];
type Params = Endpoint["Params"];
type Body = Endpoint["Body"];
type Output = Endpoint["Output"];

This is helpful for defining our own fetching functions or wrapping typed-client functionality.

export const getPost = async (params: Params): Promise<Result> => {
  // ...
};

On this page