# typed-api-fetch

> Generate a typed fetch method from a typescript definition

Latest version **0.8.0** (published 2023-09-03) · MIT license · 0 weekly downloads

## Install

```sh
npm install typed-api-fetch
pnpm add typed-api-fetch
yarn add typed-api-fetch
bun add typed-api-fetch
```

## Health

**Score 25/100 (F)** — status: abandoned.

Positive: has types; no vulnerabilities; high quality score.

Warnings: low downloads; no esm support; pre 1.0.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 0.8.0 |
| Published | 2023-09-03 |
| First published | 2023-03-14 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | CommonJS |
| Dependencies | 0 |
| Unpacked size | 35.5 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | mnorlin |
| Maintainers | mnorlin |
| Keywords | fetch, client, typescript, ts, openapi-typescript, swagger, openapi, openapi 3 |

## Links

- npm: https://www.npmjs.com/package/typed-api-fetch
- Repository: https://github.com/mnorlin/typed-api-fetch
- Homepage: https://github.com/mnorlin/typed-api-fetch#readme
- Issues: https://github.com/mnorlin/typed-api-fetch/issues
- npm.io page: https://npm.io/package/typed-api-fetch

## Alternatives

- [launchdarkly-js-client-sdk](https://npm.io/package/launchdarkly-js-client-sdk.md) — 2.5M weekly downloads
- [@elastic/elasticsearch](https://npm.io/package/@elastic/elasticsearch.md) — 2.1M weekly downloads
- [@c8y/client](https://npm.io/package/@c8y/client.md) — 15.3K weekly downloads
- [@signaldb/maverickjs](https://npm.io/package/@signaldb/maverickjs.md) — 1.7K weekly downloads
- [@bbc/http-transport-cache](https://npm.io/package/@bbc/http-transport-cache.md) — 1.2K weekly downloads

## Recent versions

- 0.8.0 (latest) — 2023-09-03
- 0.7.0 — 2023-07-21
- 0.6.2 — 2023-07-20
- 0.6.1 — 2023-07-20
- 0.6.0 — 2023-07-20
- 0.5.0 — 2023-05-08
- 0.4.0 — 2023-04-23
- 0.3.2 — 2023-03-29
- 0.3.0 — 2023-03-19
- 0.2.1 — 2023-03-18
- 0.2.0 — 2023-03-18
- 0.1.0 — 2023-03-14

## README

# typed-api-fetch

`typed-api-fetch` creates a `fetch` method that mimics the browser native `fetch`, but with added type inference.

It is primarily focused on using the TypeScript definitions generated by [openapi-typescript](https://github.com/drwpow/openapi-typescript/tree/main/packages/openapi-typescript), a tool that generates TypeScript definitions from an OpenAPI specification.

## Example

```ts
const fetch = createFetch<paths>({ baseUrl: "https://petstore3.swagger.io" });

const response = await fetch(
  "/pet/{petId}", // path autocomplete
  {
    method: "get", // available methods depending on given path
    parameters: {
      path: { petId: 42 }, // typed path parameter
    },
  }
);

const data = await response.json();

console.log(data.name);
console.log(data.age); // ❌ property 'age' does not exist
```

## Install

```bash
npm install typed-api-fetch
```

## Usage

### Generate a TypeScript definition

To generate a TypeScript definition, you can use [openapi-typescript](https://github.com/drwpow/openapi-typescript) to parse an OpenAPI specification.

```bash
npx openapi-typescript https://petstore3.swagger.io/api/v3/openapi.json --output petstore.ts

# https://petstore3.swagger.io/api/v3/openapi.json → petstore.ts [818ms]
```

### Create a `fetch` function

With a type definition stored in `./petstore.ts`, it is now possible to build a typed `fetch` client.

```ts
import { paths } from "./petstore";
import createFetch from "typed-api-fetch";

const fetch = createFetch<paths>({
  baseUrl: "https://petstore3.swagger.io",
  defaultInit: {
    headers: {
      Accept: "application/json",
    },
  },
});
```

The builder accepts the following options

| Name                     | Type       | Default                                                                                  | Description                                                                                                                                 |
| :----------------------- | :--------- | :--------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------ |
| `baseUrl`                | `string`   |                                                                                          | Prefixed to the `path` of the fetch method (eg. `https://petstore3.swagger.io`)                                                             |
| `defaultInit`            | `object`   |                                                                                          | Default options in the generated fetch method                                                                                               |
| `fetchMethod`            | `Function` | `fetch`                                                                                  | A fetch method used to call the API, must comply to the global Fetch method definition                                                      |
| `parameterSerialization` | `object`   | `{ path: { explode: false, style: "simple" }, query: { explode: false, style: "form"} }` | an object describing how `path` and `query` parameters should be [`serialized`](https://swagger.io/docs/specification/serialization/#query) |

### Call the generated `fetch` function

```ts
const fetch = createFetch<paths>();
const response = await fetch(
  "/pet/{petId}", // path autocomplete
  {
    method: "get", // available methods depending on given path
    parameters: {
      path: { petId: 42 }, // typed path parameter
    },
  }
);
```

The `fetch` function takes two arguments, `path` and `options`. `options` has the same properties as the [global `fetch` function](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options), but with a few differences.

| Name         | Type                        | Default | Description                                                                                                                        |
| :----------- | :-------------------------- | :------ | :--------------------------------------------------------------------------------------------------------------------------------- |
| `body`       | `object`                    |         | A JSON object that satisfies the API definition                                                                                    |
| `parameters` | `object`                    |         | A record with a `path` and `query` property. See the example below this table of how to use it                                     |
| `headers`    | `HeadersInit` or `function` |         | Either a valid Header constructor arguement, or a function that takes an object with `resolvedPath` and returns a valid HeaderInit |

Given the path `/pet/{petId}`, and the parameter object

```js
{
  path: { petId: 42 },
  query: { page: 3 },
}
```

the resolved path would be `/pet/42?page=3`.

### Infer the response body

An API can declare different response types for each status code.
These can be accessed via a `discriminated union` on either the `status` or `ok` property of the `response` object.

```ts
const response = await fetch("/users", { method: "get" });

if (response.ok) {
  const dataOk = await response.json(); // Infered type of HTTP 2XX status codes
}

if (response.status === 404) {
  const data404 = await response.json(); // Infered type on HTTP 404 status responses
}
```

## Utility types

The `Operation` and `Paths` are the generated types from `openapi-typescript`.

| Name                                  | Description                                                                             |
| :------------------------------------ | :-------------------------------------------------------------------------------------- |
| `FetchOptions<Operation>`             | The `options` argument for the `fetch` function from a given `Operation`                |
| `FetchParameters<Operation>`          | The `parameters` property withing `options`, containing the `path` and `query` property |
| `ResponseBody<Operation, StatusCode>` | The response body given a specific HTTP `StatusCode`                                    |
| `ResponseBodyError<Operation>`        | The response body for error responses (HTTP status code 300-599)                        |
| `ResponseBodySuccess<Operation>`      | The response body for error responses (HTTP status code 200-299)                        |
| `SubPaths<Paths, Method>`             | The paths given a specified HTTP `Method`.                                              |

### Example implmentations

Using the utility types, you can write a custom implementation using the generated `fetch` function. Below is a function that makes `GET` requests, and returns an object with `{ data, error }` depending on the response status code.

```tsx
import createFetch from "typed-api-fetch";
import type {
  ResponseBodySuccess,
  FetchOptions,
  SubPaths,
} from "typed-api-fetch";
import { paths } from "./petstore-openapi3";

const fetch = createFetch<paths>();

export async function fetchGet<
  GetPath extends SubPaths<paths, "get">,
  Operation extends paths[GetPath]["get"]
>(
  path: GetPath,
  options: FetchOptions<Operation>
): Promise<{
  data?: ResponseBodySuccess<Operation>;
  error?: ResponseBodyError<Operation>;
}> {
  const response = await fetch(path, { ...options, method: "get" });

  if (response.ok) {
    return {
      data: (await response.json()) as ResponseBodySuccess<Operation>,
      error: undefined,
    };
  } else {
    return {
      data: undefined,
      error: (await response.json()) as ResponseBodyError<Operation>,
    };
  }
}
```

## Acknowledgment

Inspired by [openapi-typescript-fetch](https://github.com/ajaishankar/openapi-typescript-fetch)

---
_Source: https://npm.io/package/typed-api-fetch · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
