shoffmeister / openapi-typescript

Generate TypeScript types from OpenAPI 3 specs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

version(scoped) npm downloads (weekly) codecov

All Contributors

๐Ÿ“˜๏ธ openapi-typescript

๐Ÿš€ Convert static OpenAPI schemas to TypeScript types quickly using pure Node.js. Fast, lightweight, (almost) dependency-free, and no Java/node-gyp/running OpenAPI servers necessary.

Features

  • โœ… Supports YAML and JSON formats
  • โœ… Supports advanced OpenAPI 3.1 features like discriminators
  • โœ… Supports loading via remote URL (simple authentication supported with the --auth flag)
  • โœ… Supports remote references: $ref: "external.yaml#components/schemas/User"
  • โœ… Fetches remote schemas quickly using undici

Examples

๐Ÿ‘€ See examples

Usage

Note:๏ธ openapiTS requires VALID OpenAPI 3.x schemas to work, and this library does not handle validation. There are several quality tools that handle this like @apidevtools/swagger-parser. Make sure to validate your schemas first!

๐Ÿ–ฅ๏ธ CLI

๐Ÿ—„๏ธ Reading a local schema

npx openapi-typescript schema.yaml --output schema.ts

# ๐Ÿ”ญ Loading spec from schema.yamlโ€ฆ
# ๐Ÿš€ schema.yaml -> schema.ts [250ms]
๐Ÿฆ  Globbing local schemas
npx openapi-typescript "specs/**/*.yaml" --output schemas/

# ๐Ÿ”ญ Loading spec from specs/one.yamlโ€ฆ
# ๐Ÿ”ญ Loading spec from specs/two.yamlโ€ฆ
# ๐Ÿ”ญ Loading spec from specs/three.yamlโ€ฆ
# ๐Ÿš€ specs/one.yaml -> schemas/specs/one.ts [250ms]
# ๐Ÿš€ specs/two.yaml -> schemas/specs/two.ts [250ms]
# ๐Ÿš€ specs/three.yaml -> schemas/specs/three.ts [250ms]

Thanks, @sharmarajdaksh!

โ˜๏ธ Reading remote schemas

npx openapi-typescript https://petstore3.swagger.io/api/v3/openapi.yaml --output petstore.d.ts

# ๐Ÿ”ญ Loading spec from https://petstore3.swagger.io/api/v3/openapi.yamlโ€ฆ
# ๐Ÿš€ https://petstore3.swagger.io/api/v3/openapi.yaml -> petstore.d.ts [650ms]

Thanks, @psmyrdek!

๐ŸŸฆ Using in TypeScript

Import any top-level item from the generated spec to use it. It works best if you also alias types to save on typing:

import { components } from "./generated-schema.ts";

type APIResponse = components["schemas"]["APIResponse"];

Because OpenAPI schemas may have invalid TypeScript characters as names, the square brackets are a safe way to access every property.

๐Ÿ—๏ธ Operations

Operations can be imported directly by their operationId:

import { operations } from "./generated-schema.ts";

type getUsersById = operations["getUsersById"];

Thanks, @gr2m!

โšพ Fetching data

Fetching data can be done simply and safely using an automatically-typed fetch wrapper:

Example (openapi-fetch)

import createClient from "openapi-fetch";
import { paths } from "./v1"; // (generated from openapi-typescript)

const { get, post, put, patch, del } = createClient<paths>({
  baseURL: "https://myserver.com/api/v1/",
  headers: {
    Authorization: `Bearer ${import.meta.env.VITE_AUTH_TOKEN}`,
  },
});

See each projectโ€™s respective pages for usage & install instructions.

โœจ Tip: Automatically-typed fetch wrappers are better to use than manually-assigned generics. The latter is not only more work, but it can be error-prone (which makes your OpenAPI typing worthless if it canโ€™t catch all your errors!).

๐Ÿ“– Options

The following flags can be appended to the CLI command.

Option Alias Default Description
--help Display inline help message and exit
--version Display this libraryโ€™s version and exit
--output [location] -o (stdout) Where should the output file be saved?
--auth [token] Provide an auth token to be passed along in the request (only if accessing a private schema)
--header -x Provide an array of or singular headers as an alternative to a JSON object. Each header must follow the key: value pattern
--headers-object="{โ€ฆ}" -h Provide a JSON object as string of HTTP headers for remote schema request. This will take priority over --header
--http-method -m GET Provide the HTTP Verb/Method for fetching a schema from a remote URL
--immutable-types false Generates immutable types (readonly properties and readonly array)
--additional-properties false Allow arbitrary properties for all schema objects without additionalProperties: false
--empty-objects-unknown false Allow arbitrary properties for schema objects with no specified properties, and no specified additionalProperties
--default-non-nullable false Treat schema objects with default values as non-nullable
--export-type -t false Export type instead of interface
--path-params-as-types false Allow dynamic string lookups on the paths object
--support-array-length false Generate tuples using array minItems / maxItems
--alphabetize false Sort types alphabetically

๐Ÿšฉ --path-params-as-types

By default, your URLs are preserved exactly as-written in your schema:

export interface paths {
  "/user/{user_id}": components["schemas"]["User"];
}

Which means your type lookups also have to match the exact URL:

import { paths } from "./my-schema";

const url = `/user/${id}`;
type UserResponses = paths["/user/{user_id}"]["responses"];

But when --path-params-as-types is enabled, you can take advantage of dynamic lookups like so:

import { paths } from "./my-schema";

const url = `/user/${id}`;
type UserResponses = paths[url]["responses"]; // automatically matches `paths['/user/{user_id}']`

Though this is a contrived example, you could use this feature to automatically infer typing based on the URL in a fetch client or in some other useful place in your application.

Thanks, @Powell-v2!

๐Ÿšฉ --support-array-length

This option is useful for generating tuples if an array type specifies minItems or maxItems.

For example, given the following schema:

components:
  schemas:
    TupleType
      type: array
      items:
        type: string
      minItems: 1
      maxItems: 2

Enabling --support-array-length would change the typing like so:

  export interface components {
    schemas: {
-     TupleType: string[];
+     TupleType: [string] | [string, string];
    };
  }

This results in more explicit typechecking of array lengths.

Note: this has a reasonable limit, so for example maxItems: 100 would simply flatten back down to string[];

Thanks, @kgtkr!

๐Ÿข Node

npm i --save-dev openapi-typescript
import fs from "node:fs";
import openapiTS from "openapi-typescript";

// example 1: load [object] as schema (JSON only)
const schema = await fs.promises.readFile("spec.json", "utf8"); // must be OpenAPI JSON
const output = await openapiTS(JSON.parse(schema));

// example 2: load [string] as local file (YAML or JSON; released in v4.0)
const localPath = new URL("./spec.yaml", import.meta.url); // may be YAML or JSON format
const output = await openapiTS(localPath);

// example 3: load [string] as remote URL (YAML or JSON; released in v4.0)
const output = await openapiTS("https://myurl.com/v1/openapi.yaml");

The Node API may be useful if dealing with dynamically-created schemas, or youโ€™re using within context of a larger application. Pass in either a JSON-friendly object to load a schema from memory, or a string to load a schema from a local file or remote URL (it will load the file quickly using built-in Node methods). Note that a YAML string isnโ€™t supported in the Node.js API; either use the CLI or convert to JSON using js-yaml first.

๐Ÿ“– Node options

The Node API supports all the CLI flags above in camelCase format, plus the following additional options:

Name Type Default Description
commentHeader string Override the default โ€œThis file was auto-generated โ€ฆโ€ file heading
inject string Inject arbitrary TypeScript types into the start of the file
transform Function Override the default Schema Object โž TypeScript transformer in certain scenarios
postTransform Function Same as transform but runs after the TypeScript transformation

๐Ÿค– transform / postTransform

If using the Node.js API, you can override the normal Schema Object transformer with your own. This is useful for providing enhanced functionality for specific parts of your schema.

For example, say your schema has the following property:

properties:
  updated_at:
    type: string
    format: date-time

By default, openapiTS will generate updated_at?: string; because itโ€™s not sure which format you want by "date-time" (formats are nonstandard and can be whatever youโ€™d like). But we can enhance this by providing our own custom formatter, like so:

const types = openapiTS(mySchema, {
  transform(schemaObject, metadata): string {
    if ("format" in schemaObject && schemaObject.format === "date-time") {
      return schemaObject.nullable ? "Date | null" : "Date";
    }
  },
});

That would result in the following change:

-  updated_at?: string;
+  updated_at?: Date;

Any Schema Object present in your schema will be run through this formatter (even remote ones!). Also be sure to check the metadata parameter for additional context that may be helpful.

There are many other uses for this besides checking format. Because this must return a string you can produce any arbitrary TypeScript code youโ€™d like (even your own custom types).

โœจ Donโ€™t forget about postTransform() as well! It works the same way, but runs after the TypeScript transformation so you can extend/modify types as-needed.

๐Ÿ… Project Goals

  1. Support converting any valid OpenAPI schema to TypeScript types, no matter how complicated.
  2. This library does NOT validate your schema, there are other libraries for that.
  3. The generated TypeScript types must match your schema as closely as possible (e.g. no renaming to PascalCase)
  4. This library should never require Java, node-gyp, or some other complex environment to work. This should require Node.js and nothing else.
  5. This library will never require a running OpenAPI server to work.

๐Ÿค Contributing

PRs are welcome! Please see our CONTRIBUTING.md guide.

Contributors โœจ

Thanks goes to these wonderful people (emoji key):

Drew Powers
Drew Powers

๐Ÿ’ป ๐Ÿ“– ๐Ÿš‡ โš ๏ธ
Przemek Smyrdek
Przemek Smyrdek

๐Ÿ’ป ๐Ÿ“– ๐Ÿค” โš ๏ธ
Dan Enman
Dan Enman

๐Ÿ› ๐Ÿ’ป
Atle Frenvik Sveen
Atle Frenvik Sveen

๐Ÿ’ป ๐Ÿ“– ๐Ÿค” โš ๏ธ
Tim de Wolf
Tim de Wolf

๐Ÿ’ป ๐Ÿค”
Tom Barton
Tom Barton

๐Ÿ’ป ๐Ÿ“– ๐Ÿค” โš ๏ธ
Sven Nicolai Viig
Sven Nicolai Viig

๐Ÿ› ๐Ÿ’ป โš ๏ธ
Sorin Davidoi
Sorin Davidoi

๐Ÿ› ๐Ÿ’ป โš ๏ธ
Nathan Schneirov
Nathan Schneirov

๐Ÿ’ป ๐Ÿ“– ๐Ÿค” โš ๏ธ
Lucien Bรฉniรฉ
Lucien Bรฉniรฉ

๐Ÿ’ป ๐Ÿ“– ๐Ÿค” โš ๏ธ
Boris K
Boris K

๐Ÿ“–
Anton
Anton

๐Ÿ› ๐Ÿ’ป ๐Ÿค” โš ๏ธ
Tim Shelburne
Tim Shelburne

๐Ÿ’ป โš ๏ธ
Michaล‚ Miszczyszyn
Michaล‚ Miszczyszyn

๐Ÿ’ป
Sam K Hall
Sam K Hall

๐Ÿ’ป โš ๏ธ
Matt Jeanes
Matt Jeanes

๐Ÿ’ป
Kristofer Giltvedt Selbekk
Kristofer Giltvedt Selbekk

๐Ÿ’ป
Elliana May
Elliana May

๐Ÿ’ป โš ๏ธ
Henrik Hall
Henrik Hall

๐Ÿ’ป ๐Ÿ“– โš ๏ธ
Gregor Martynus
Gregor Martynus

๐Ÿ’ป โš ๏ธ ๐Ÿ›
Sam Mesterton-Gibbons
Sam Mesterton-Gibbons

๐Ÿ’ป ๐Ÿ› โš ๏ธ
Rendall
Rendall

๐Ÿ’ป ๐Ÿ› โš ๏ธ
Robert Massaioli
Robert Massaioli

๐Ÿ’ป ๐Ÿ›
Jan Kuฤa
Jan Kuฤa

๐Ÿ’ป โš ๏ธ
Thomas Valadez
Thomas Valadez

๐Ÿ“–
Asitha de Silva
Asitha de Silva

๐Ÿ’ป ๐Ÿ›
Mikhail Yermolayev
Mikhail Yermolayev

๐Ÿ›
Alex Batalov
Alex Batalov

๐Ÿ’ป โš ๏ธ
Federico Bevione
Federico Bevione

๐Ÿ› ๐Ÿ’ป โš ๏ธ
Daisuke Yamamoto
Daisuke Yamamoto

๐Ÿ’ป ๐Ÿ› โš ๏ธ
dnalborczyk
dnalborczyk

๐Ÿ“– ๐Ÿ’ป โš ๏ธ
FabioWanner
FabioWanner

๐Ÿ› ๐Ÿ’ป โš ๏ธ
Ash Smith
Ash Smith

๐Ÿ’ป ๐Ÿ› โš ๏ธ
Micah Halter
Micah Halter

๐Ÿ’ป โš ๏ธ ๐Ÿ›
Yuto Yoshihara
Yuto Yoshihara

๐Ÿ’ป ๐Ÿ› โš ๏ธ
Dakshraj Sharma
Dakshraj Sharma

๐Ÿ’ป
Shaosu Liu
Shaosu Liu

๐Ÿ’ป
Vytenis
Vytenis

๐Ÿ’ป
Eric Zorn
Eric Zorn

๐Ÿ’ป โš ๏ธ ๐Ÿ“–
Max Belsky
Max Belsky

๐Ÿ’ป ๐Ÿ›
Peter Bech
Peter Bech

๐Ÿ’ป ๐Ÿ›
Rusty Conover
Rusty Conover

๐Ÿ’ป
Dave Carlson
Dave Carlson

๐Ÿ’ป
ottomated
ottomated

๐Ÿ’ป ๐Ÿ›
Artem Shuvaev
Artem Shuvaev

๐Ÿ’ป ๐Ÿ›
ajaishankar
ajaishankar

๐Ÿ“–
Dominik Dosoudil
Dominik Dosoudil

๐Ÿ’ป โš ๏ธ
tkr
tkr

๐Ÿ’ป ๐Ÿ“–
berzi
berzi

๐Ÿ’ป ๐Ÿ“– โš ๏ธ
Philip Trauner
Philip Trauner

๐Ÿ’ป ๐Ÿ“– โš ๏ธ
Pavel Yermolin
Pavel Yermolin

๐Ÿ’ป ๐Ÿ“– โš ๏ธ
Duncan Beevers
Duncan Beevers

๐Ÿ’ป ๐Ÿ› โš ๏ธ ๐Ÿ“–
Timofey Kukushkin
Timofey Kukushkin

๐Ÿ’ป โš ๏ธ ๐Ÿ›
Dmitry Semigradsky
Dmitry Semigradsky

๐Ÿ› โš ๏ธ ๐Ÿ’ป
Jeremy Liberman
Jeremy Liberman

๐Ÿ’ป โš ๏ธ
Axel Hernรกndez Ferrera
Axel Hernรกndez Ferrera

๐Ÿ’ป ๐Ÿ› โš ๏ธ
Loรฏc Fรผrhoff
Loรฏc Fรผrhoff

๐Ÿ’ป โš ๏ธ ๐Ÿ›
Bartosz Szczeciล„ski
Bartosz Szczeciล„ski

๐Ÿ’ป ๐Ÿ› โš ๏ธ
Marco Salomone
Marco Salomone

๐Ÿ’ป โš ๏ธ ๐Ÿ›
Yacine Hmito
Yacine Hmito

๐Ÿ’ป โš ๏ธ ๐Ÿ›
Sajad Torkamani
Sajad Torkamani

๐Ÿ“–
Marius van den Beek
Marius van den Beek

๐Ÿ’ป ๐Ÿ› โš ๏ธ
Steven Grimm
Steven Grimm

๐Ÿ’ป ๐Ÿ› โš ๏ธ
Erik Hughes
Erik Hughes

๐Ÿ’ป ๐Ÿ› โš ๏ธ
Matthieu Monsch
Matthieu Monsch

๐Ÿ’ป ๐Ÿ› โš ๏ธ
Mitchell Merry
Mitchell Merry

๐Ÿ’ป โš ๏ธ ๐Ÿ›
Franรงois Risoud
Franรงois Risoud

๐Ÿ’ป ๐Ÿ› โš ๏ธ

This project follows the all-contributors specification. Contributions of any kind welcome!

About

Generate TypeScript types from OpenAPI 3 specs

License:MIT License


Languages

Language:TypeScript 95.7%Language:JavaScript 4.3%