Code Monkey home page Code Monkey logo

oazapfts's Introduction

๐Ÿป oazapfts!

CI semantic-release: angular

Generate TypeScript clients to tap into OpenAPI servers.

Features

  • AST-based: Unlike other code generators oazapfts does not use templates to generate code but uses TypeScript's built-in API to generate and pretty-print an abstract syntax tree.
  • Fast: The CLI does not use any of the common Java-based tooling, so the code generation is super fast.
  • Single file: All functions and types are co-located in one single self-contained file.
  • Tree-shakeable: Individually exported functions allow you to bundle only the ones you actually use.
  • Human friendly signatures: The generated API methods don't leak any HTTP-specific implementation details. For example, all optional parameters are grouped together in one object, no matter whether they end up in the headers, path or query-string.

Installation

npm install oazapfts

Note With version 3.0.0 oazapfts has become a runtime dependency and the generated code does no longer include all the fetch logic.

Usage

oazapfts <spec> [filename]

Options:
--exclude, -e tag to exclude
--include, -i tag to include
--optimistic
--useEnumType
--mergeReadWriteOnly

Where <spec> is the URL or local path of an OpenAPI or Swagger spec (in either json or yml) and <filename> is the location of the .ts file to be generated. If the filename is omitted, the code is written to stdout.

Options

  • --optimistic generare a client in optimistic mode

  • --useEnumType generate enums instead of union types

  • --mergeReadWriteOnly by default oazapfs will generate separate types for read-only and write-only properties. This option will merge them into one type.

Consuming the generated API

For each operation defined in the spec the generated API will export a function with a name matching the operationId. If no ID is specified, a reasonable name is generated from the HTTP verb and the path.

import * as api from "./my-generated-api.ts";
const res = api.getPetById(1);

Note If your API is large, and you want to take advantage of tree-shaking to exclude unused code, use individual named imports instead:

import { getPetById } from "./my-generated-api.ts";

Fetch options

The last argument of each function is an optional RequestOpts object that can be used to pass options to the fetch call, for example to pass additional headers or an AbortSignal to cancel the request later on.

const res = getPetById(1, {
  credentials: "include",
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

You can also use this to override the default baseUrl or to provide a custom fetch implementation.

Note Instead of passing custom options to each function call, consider overwriting the global defaults.

Optimistic vs. explicit responses

Oazapfts supports two different modes to handle results, an explicit mode (the default) and an optimistic mode, that makes the response handling less verbose.

Explicit mode

By default, each function returns an ApiResponse object that exposes the status code, response headers and the data.

Note This mode is best suited for APIs that return different types for different response codes or APIs where you need to access not only the response body, but also the response headers. If your API is simple, and you don't need this flexibility, consider using the optimistic mode instead.

In explicit mode, each function returns a Promise for an ApiResponse which is an object with a status and a data property, holding the HTTP status code and the properly typed data from the response body.

Since an operation can return different types depending on the status code, the actual return type is a union of all possible responses, discriminated by their status.

Consider the following code generated from the petstore.json example:

/**
 * Find pet by ID
 */
export function getPetById(petId: number, opts?: Oazapfts.RequestOpts) {
  return oazapfts.fetchJson<
    | {
        status: 200;
        data: Pet;
      }
    | {
        status: 400;
        data: string;
      }
    | {
        status: 404;
      }
  >(`/pet/${encodeURIComponent(petId)}`, {
    ...opts,
  });
}

In this case, the data property is typed as Pet|string. We can use a type guard to narrow down the type to Pet:

const res = await api.getPetById(1);
if (res.status === 200) {
  const pet = res.data;
  // pet is properly typed as Pet
}
if (res.status === 404) {
  const message = res.data;
  // message is a string
} else {
  // handle the error
}

The above code can be simplified by using the handle helper:

import { handle } from "oazapfts";

await handle(api.getPetById(1), {
  200(pet) {
    // pet is properly typed as Pet
  },
  404(message) {
    // message is as string
  },
});

The helper will throw an HttpError error for any unhandled status code, unless you add a default handler:

await handle(api.getPetById(1), {
  200(pet) {
    // ...
  },
  default(status, data) {
    // handle error
  },
});

Optimistic mode

You can opt into the optimistic mode by using the --optimistic command line argument.

In this mode, each function will return a Promise for the happy path, i.e. the type specified for the first 2xx response.

Looking back at our Pet Store example from above, consuming the response is now much easier and less verbose:

const pet = await api.getPetById(1);
// pet is now typed as Pet!

In case of a response other than 200 the promise will be rejected with a HttpError.

Mixing both modes

Sometimes you might want to use the optimistic mode for some of your API calls, but need the full ApiResponse for others.

In that case, you can use the ok-helper function to selectively apply optimistic response handling:

import { ok } from "oazapfts";

const pet = await ok(api.getPetById(1));

Overriding the defaults

The generated file exports a defaults constant that can be used to override the basePath, provide a custom fetch implementation or to send additional headers with each request. Basically, you can set a default for any fetch option you want.

import * as api from "./api.ts";
import nodeFetch from "node-fetch";

// Override the spec's basePath
api.defaults.basePath = "https://example.com/api";

// Send this header with each request
api.defaults.headers = {
  access_token: "secret",
};

// Include credentials in CORS requests, too
api.defaults.credentials = "include";

// Use this instead of the global fetch
api.defaults.fetch = nodeFetch;

Alternatives and integrations

If this library doesn't fit your needs, take a look at openapi-typescript-codegen which follows a similar philosophy but creates many individual files instead of one single self-contained file.

If your frontend uses React, take a look at react-api-query which makes it easy to use an oazapfts client with React hooks in a convenient and type-safe way.

About the name

The name comes from a combination of syllables oa (OpenAPI) and ts (TypeScript) and is pronounced ๐Ÿ—ฃ like the Bavarian O'zapt'is! (it's tapped), the famous words that mark the beginning of the Oktoberfest.

License

MIT

oazapfts's People

Contributors

asemy avatar bdm-k avatar cvereterra avatar dependabot[bot] avatar dlehmhus avatar ehvattum avatar eric-carlsson avatar fgnass avatar jonkoops avatar kahirokunn avatar kmirojo avatar kosky37 avatar labmorales avatar lindapaiste avatar mikeralphson avatar mo-hh234 avatar mrtnvh avatar nvveen avatar olof-nord avatar phryneas avatar qqilihq avatar rtfpessoa avatar saschahofmann avatar shocklateboy92 avatar smiley-uriux avatar swernerx avatar timmbuktu avatar tmueller avatar trim21 avatar xiphe 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.