npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

unclient

v0.2.0

Published

👮‍♀️ Type-safe interactions with any HTTP API

Downloads

60

Readme

Unclient

Unclient is a tiny, minimalistic utility for interacting with HTTP APIs with type-safety, whether it's your API or not.

npm i unclient

Features

  • [x] Works with any HTTP API
  • [x] Infer OpenAPI spec types without codegen
  • [x] Implement custom fetchers
  • [x] Unopinionated API
  • [x] Implemented in simple JavaScript (i.e. no proxy objects)

Example Usage

import { DefineApp } from "unclient";

// Define the endpoints (or generate from backend/OpenAPI)
type Api = DefineApi<{
  "GET /foo/:id": {
    Query: {
      foo: string;
    };
    Params: {
      id: string;
    };
  };
}>;

// Create an unclient
const client = createUnclient<Api>({
  fetcher: myFetcher,
});

const getFoo = client("GET /foo/:id");

const result = await getFoo({
  query: { foo: string },
  params: { id: "abc" },
});

Table of Contents

Why?

Typed API clients are a standard feature of any modern web, mobile or backend app. However, the API contract is often defined implicitly throughout our codebase. Moreover, defining each type manually can be laborious, error prone and hard to track.

Unclient let's us define a single source of truth for our API contract. Further, we can export type definitions from our backend or generate them from OpenAPI specs. In turn, we can enjoy type safe clients without owning the API in question nor requiring buy-in to a full-stack backend framework.

How?

By providing type description of a backend, whether defined on the client-side, backend or through OpenAPI specs, unclient reads this description and provides an ergonomic, tiny client. Since unclient is agnostic to how exactly your fetches are made, it doesn't get in your way.

API Reference

DefineApi<T>

A helper type for defining API endpoints.

With DefineApi, we provide a record of path and schema pairs. Each path may specify the following fields:

  • Query: Query parameters
  • Params: Path parameters
  • Body: Request body
  • Output: Response body
type MyApi = DefineApi<{
  "GET /post/:id": {
    Query: {
      limit: number;
    };
    Params: {
      id: string;
    };
    Body: {
      foo: string;
    };
    Output: {
      bar: string;
    };
  };
}>;

Using OpenAPI specs

We can automatically infer types from an OpenAPI JSON spec using the spec-dts package. The resulting API type definition is compatible with Unclient.

createUnclient<ApiDef>(opts)

Creates a new API client

To intialise a new client we must provide our API definition and a custom fetcher function.

The fetcher function receives a config parameter, which includes all of the necessary information for building a request. How that request is sent is intentionally up to you.

import { createUrl } from "unclient";

const client = createUnclient<MyApi>({
  fetcher: (config, ...rest) => {
    const { query, params, body, method, path } = config;

    // Use the `createUrl` utility to more easily derive the URL from `config`
    const url = createUrl(config);

    // ...turn the above into a `fetch`, `axios` etc. request config...

    return {
      data: {}, // Becomes the `Output` when invoking the client
    };
  },
});

Return Type

To capture the output type of the API response properly, while also enabling returning any additional information, the fetcher expects an object to be returned. The response body (if any) should be provided as a special data field, which will "inherit" the correct Output type, when the client is invoked.

const result = await getPosts(/** ... */);

const { data, ...rest } = result;

data;
// { bar: string }

rest;
// ...whatever else was returned

This opens the door to returning additional useful information like response headers or statusses (or anything else).

Custom parameters

The ...rest params allow specifying arbitrary additional parameters to be passed to any client calls. For example, you might want to pass additional options to your fetching library of choice.

const client = createUnclient<MyApi>({
  fetcher: (config, options: RequestInit) => {
    // ...
    fetch(url, options);
    // ...
  },
});

// ...and when using the client

const result = getPosts(config, {
  headers: new Headers(),
});