Natural Performance Manager

    openapi-typescript
    TypeScript icon, indicating that this package has built-in type declarations

    6.1.0 • Public • Published

    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

    Simple example

    Any fetch call can be typed from the paths like so:

    import { paths } from './my-types';
    
    const response: paths["/api/v1/user/{user_id}"]["get"][200 | 500] = await fetch(`/api/v1/user/${user_id}`).then((res) => res.json());

    Or if you add the --path-params-as-types CLI flag, you can take advantage of more automatic inference:

    import { paths } from './my-types';
    
    const url = `/api/v1/user/${user_id}`;
    const response: paths[url]["get"][200 | 500] = await fetch(url).then((res) => res.json());
    openapi-typescript-fetch

    You can generate a fully-typed Fetch API client from openapiTS types with the openapi-typescript-fetch package:

    import { paths } from "./petstore";
    import { Fetcher } from "openapi-typescript-fetch";
    
    const fetcher = Fetcher.for<paths>();
    
    // GET
    const findPetsByStatus = fetcher.path("/pet/findByStatus").method("get").create();
    const { status, data: pets } = await findPetsByStatus({
      status: ["available", "pending"],
    });
    
    // POST
    const addPet = fetcher.path("/pet").method("post").create();
    await addPet({ ... })

    See docs

    Thanks, @ajaishankar!

    📖 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
    --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 "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

    💻 ⚠️ 🐛

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

    Install

    npm i openapi-typescript

    DownloadsWeekly Downloads

    151,952

    Version

    6.1.0

    License

    MIT

    Unpacked Size

    293 kB

    Total Files

    68

    Last publish

    Collaborators

    • drewpowers