0.7.0 • Published 1 year ago

openapi2typescript-cli v0.7.0

Weekly downloads
14
License
Apache-2.0
Repository
-
Last release
1 year ago

openapi2typescript-cli

Command line utility to generate zod schemas from an OpenApi schema. These shemas do not only help to have a "typed" response, but they can ensure (by running a validation) that you actually got the type you are expecting.

Despite its name, you can also use it in plain js for running the validations (i.e. skip the types generation).

Installing

You can either install openapi2typescript-cli package as a dev-dependency or run it using npx. You are also required to install openapi2typescript as a dependency, as the generated code makes use of that library in most of the cases.

npm install openapi2typescript
npx openapi2typescript-cli 

Usage

To use, you must run the binary npm run openapi2typescript or with npx npx openapi2typescript-cli. You must specify the input file or url to the openapi and the output file, see the Options for more info.

You can see the lib usage at: openapi2typescript

Options

--input

URL or local path to an openapi.json file. If using URL, the Accept: application/json will be provided in the request.

--output

Output file or path to place the result. If using a directory, a file Generated.ts will be created there.

--skip-post-process

Skips the post process which prettier and eslint on the output.

--action-generator

Complementary code to help hook into a third party library, at the moment only react-fetching-library is supported, but more are welcome.

Default: none

none

Does not generate any other code.

react-fetching-library

Generates action generators for react-fetching-library

--add-eslint-disable

Convenient method to disable eslint on the file. i.e. it adds /* eslint-disable */ on top of the file.

--skip-types

Prevent Typescript types from appearing in the output, so that the output is js-friendly.

--no-strict

Use the nonstrict checking behavior of zod for all the objects.

--explicit-types (EXPERIMENTAL)

By default, zod will fail if an object comes with extra properties. With this flag, it won't fail if there are extra properties.

Example

Given the following example:

{
  "openapi" : "3.0.3",
  "info" : {
    "title" : "Generated API",
    "version" : "1.0"
  },
  "paths" : {
    "/fruits" : {
      "get" : {
        "responses" : {
          "200" : {
            "description" : "OK",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/SetFruit"
                }
              }
            }
          }
        }
      },
      "post" : {
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/Fruit"
              }
            }
          }
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/SetFruit"
                }
              }
            }
          }
        }
      },
      "delete" : {
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/Fruit"
              }
            }
          }
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/SetFruit"
                }
              }
            }
          },
          "400" : {
            "description" : "Error",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Message"
                }
              }
            }
          }
        }
      }
    }
  },
  "components" : {
    "schemas" : {
      "Fruit" : {
        "type" : "object",
        "properties" : {
          "description" : {
            "type" : "string"
          },
          "name" : {
            "type" : "string"
          }
        }
      },
      "Message" : {
        "type" : "object",
        "properties" : {
          "description" : {
            "type" : "string"
          }
        }
      },
      "SetFruit" : {
        "uniqueItems" : true,
        "type" : "array",
        "items" : {
          "$ref" : "#/components/schemas/Fruit"
        }
      }
    }
  }
}

Here are some results testing different flags:

Only required arguments:

npx -i openapi.json -o result.ts
/**
 * Generated code, DO NOT modify directly.
 */
import * as z from 'zod';

export const Fruit = zodSchemaFruit();
export type Fruit = z.infer<typeof Fruit>;

export const Message = zodSchemaMessage();
export type Message = z.infer<typeof Message>;

export const SetFruit = zodSchemaSetFruit();
export type SetFruit = z.infer<typeof SetFruit>;

export function zodSchemaFruit() {
    return z.object({
        description: z.string().optional().nullable(),
        name: z.string().optional().nullable()
    });
}

export function zodSchemaMessage() {
    return z.object({
        description: z.string().optional().nullable()
    });
}

export function zodSchemaSetFruit() {
    return z.array(Fruit);
}

With --action-generator react-fetching-library

npx -i openapi.json -o result.ts --action-generator react-fetching-library
/**
 * Generated code, DO NOT modify directly.
 */
import * as z from 'zod';
import { ValidatedResponse } from 'openapi2typescript';
import { Action } from 'react-fetching-library';
import {
    actionBuilder,
    ActionValidatableConfig
} from 'openapi2typescript/react-fetching-library';

export const Fruit = zodSchemaFruit();
export type Fruit = z.infer<typeof Fruit>;

export const Message = zodSchemaMessage();
export type Message = z.infer<typeof Message>;

export const SetFruit = zodSchemaSetFruit();
export type SetFruit = z.infer<typeof SetFruit>;

// GET /fruits
export type GetFruitsPayload =
  | ValidatedResponse<'SetFruit', 200, SetFruit>
  | ValidatedResponse<'unknown', undefined, unknown>;
export type ActionGetFruits = Action<GetFruitsPayload, ActionValidatableConfig>;
export const actionGetFruits = (): ActionGetFruits => {
    const path = '/fruits';
    const query = {} as Record<string, any>;
    return actionBuilder('GET', path)
    .queryParams(query)
    .config({
        rules: [{ status: 200, zod: SetFruit, type: 'SetFruit' }]
    })
    .build();
};

// POST /fruits
export interface PostFruits {
  body: Fruit;
}

export type PostFruitsPayload =
  | ValidatedResponse<'SetFruit', 200, SetFruit>
  | ValidatedResponse<'unknown', undefined, unknown>;
export type ActionPostFruits = Action<
  PostFruitsPayload,
  ActionValidatableConfig
>;
export const actionPostFruits = (params: PostFruits): ActionPostFruits => {
    const path = '/fruits';
    const query = {} as Record<string, any>;
    return actionBuilder('POST', path)
    .queryParams(query)
    .data(params.body)
    .config({
        rules: [{ status: 200, zod: SetFruit, type: 'SetFruit' }]
    })
    .build();
};

// DELETE /fruits
export interface DeleteFruits {
  body: Fruit;
}

export type DeleteFruitsPayload =
  | ValidatedResponse<'SetFruit', 200, SetFruit>
  | ValidatedResponse<'Message', 400, Message>
  | ValidatedResponse<'unknown', undefined, unknown>;
export type ActionDeleteFruits = Action<
  DeleteFruitsPayload,
  ActionValidatableConfig
>;
export const actionDeleteFruits = (
    params: DeleteFruits
): ActionDeleteFruits => {
    const path = '/fruits';
    const query = {} as Record<string, any>;
    return actionBuilder('DELETE', path)
    .queryParams(query)
    .data(params.body)
    .config({
        rules: [
            { status: 200, zod: SetFruit, type: 'SetFruit' },
            { status: 400, zod: Message, type: 'Message' }
        ]
    })
    .build();
};

export function zodSchemaFruit() {
    return z.object({
        description: z.string().optional().nullable(),
        name: z.string().optional().nullable()
    });
}

export function zodSchemaMessage() {
    return z.object({
        description: z.string().optional().nullable()
    });
}

export function zodSchemaSetFruit() {
    return z.array(Fruit);
}

--skip-types

npx -i openapi.json -o result.js --skip-types
/**
 * Generated code, DO NOT modify directly.
 */
import * as z from 'zod';

export const Fruit = zodSchemaFruit();

export const Message = zodSchemaMessage();

export const SetFruit = zodSchemaSetFruit();

export function zodSchemaFruit() {
    return z.object({
        description: z.string().optional().nullable(),
        name: z.string().optional().nullable()
    });
}

export function zodSchemaMessage() {
    return z.object({
        description: z.string().optional().nullable()
    });
}

export function zodSchemaSetFruit() {
    return z.array(Fruit);
}

--explicit-types

npx -i openapi.json -o result.ts --explicit-types
/**
 * Generated code, DO NOT modify directly.
 */
import * as z from 'zod';

export const Fruit = zodSchemaFruit();
export type Fruit = {
  description?: string | undefined | null;
  name?: string | undefined | null;
};

export const Message = zodSchemaMessage();
export type Message = {
  description?: string | undefined | null;
};

export const SetFruit = zodSchemaSetFruit();
export type SetFruit = Array<Fruit>;

export function zodSchemaFruit() {
    return z.object({
        description: z.string().optional().nullable(),
        name: z.string().optional().nullable()
    });
}

export function zodSchemaMessage() {
    return z.object({
        description: z.string().optional().nullable()
    });
}

export function zodSchemaSetFruit() {
    return z.array(Fruit);
}

--action-generator react-fetching-library --skip-types

npx -i openapi.json -o result.js --action-generator react-fetching-library --skip-types
/**
 * Generated code, DO NOT modify directly.
 */
import * as z from 'zod';
import { actionBuilder } from 'openapi2typescript/react-fetching-library';

export const Fruit = zodSchemaFruit();

export const Message = zodSchemaMessage();

export const SetFruit = zodSchemaSetFruit();

// GET /fruits
export const actionGetFruits = () => {
    const path = '/fruits';
    const query = {};
    return actionBuilder('GET', path)
    .queryParams(query)
    .config({
        rules: [{ status: 200, zod: SetFruit, type: 'SetFruit' }]
    })
    .build();
};

// POST /fruits
/*
 Params
body: Fruit
*/
export const actionPostFruits = (params) => {
    const path = '/fruits';
    const query = {};
    return actionBuilder('POST', path)
    .queryParams(query)
    .data(params.body)
    .config({
        rules: [{ status: 200, zod: SetFruit, type: 'SetFruit' }]
    })
    .build();
};

// DELETE /fruits
/*
 Params
body: Fruit
*/
export const actionDeleteFruits = (params) => {
    const path = '/fruits';
    const query = {};
    return actionBuilder('DELETE', path)
    .queryParams(query)
    .data(params.body)
    .config({
        rules: [
            { status: 200, zod: SetFruit, type: 'SetFruit' },
            { status: 400, zod: Message, type: 'Message' }
        ]
    })
    .build();
};

export function zodSchemaFruit() {
    return z.object({
        description: z.string().optional().nullable(),
        name: z.string().optional().nullable()
    });
}

export function zodSchemaMessage() {
    return z.object({
        description: z.string().optional().nullable()
    });
}

export function zodSchemaSetFruit() {
    return z.array(Fruit);
}
0.7.0

1 year ago

0.6.1

2 years ago

0.6.0

2 years ago

0.5.1

2 years ago

0.5.0

3 years ago

0.4.3

3 years ago

0.4.2

3 years ago

0.4.1

3 years ago

0.4.0

3 years ago

0.3.1

3 years ago

0.3.0

4 years ago

0.2.3

4 years ago

0.2.2

4 years ago

0.2.1

4 years ago

0.2.0

4 years ago

0.1.0

4 years ago

0.0.5

4 years ago

0.0.4

4 years ago

0.0.1

4 years ago