TS 中文文档 TS 中文文档
指南
GitHub (opens new window)
指南
GitHub (opens new window)
  • 入门教程

    • TypeScript 手册
    • 基础知识
    • 日常类型
    • 类型缩小
    • 更多关于函数
    • 对象类型
    • 从类型创建类型
    • 泛型
    • Keyof 类型运算符
    • Typeof 类型运算符
    • 索引访问类型
    • 条件类型
    • 映射类型
    • 模板字面类型
    • 类
    • 模块
  • 参考手册

  • 项目配置

@himenon/openapi-typescript-code-generator


日本語

This library provides TypeScript type definitions and extracted parameters from OpenAPI v3.0.x compliant specifications. TypeScript AST is used to generate the code, which is accurately converted to TypeScript code. Since the parameters extracted from OpenAPI can be used freely, it can be used for automatic generation of API Client and Server Side code, load balancer configuration files, etc.

Playground


Playground

Installation


  1. ``` shell
  2. npm  i   -D @himenon/openapi-typescript-code-generator
  3. # or
  4. pnpm i   -D @himenon/openapi-typescript-code-generator
  5. # or
  6. yarn add -D @himenon/openapi-typescript-code-generator
  7. ```

DEMO


Short DEMO
DEMO: github/rest-api-client code generate
https://github.com/github/rest-api-description

Usage


The example shown here can be cloned from the DEMO repository to see how it works.

Generate typedef-only code


  1. ``` ts
  2. import * as fs from "fs";

  3. import { CodeGenerator } from "@himenon/openapi-typescript-code-generator";

  4. const main = () => {
  5.   const codeGenerator = new CodeGenerator("your/openapi/spec.yml");
  6.   const code = codeGenerator.generateTypeDefinition();
  7.   fs.writeFileSync("client.ts", code, { encoding: "utf-8" });
  8. };

  9. main();
  10. ```

Generate code containing the API Client


  1. ``` ts
  2. import * as fs from "fs";

  3. import { CodeGenerator } from "@himenon/openapi-typescript-code-generator";
  4. import * as Templates from "@himenon/openapi-typescript-code-generator/templates";
  5. import type * as Types from "@himenon/openapi-typescript-code-generator/types";

  6. const main = () => {
  7.   const codeGenerator = new CodeGenerator("your/openapi/spec.yml");

  8.   const apiClientGeneratorTemplate: Types.CodeGenerator.CustomGenerator<Templates.FunctionalApiClient.Option> = {
  9.     generator: Templates.FunctionalApiClient.generator,
  10.     option: {},
  11.   };

  12.   const code = codeGenerator.generateTypeDefinition([
  13.     codeGenerator.getAdditionalTypeDefinitionCustomCodeGenerator(),
  14.     apiClientGeneratorTemplate,
  15.   ]);

  16.   fs.writeFileSync("client.ts", code, { encoding: "utf-8" });
  17. };

  18. main();
  19. ```

The variation of template code


This library provides three types of templates

  1. ``` ts
  2. import * as Templates from "@himenon/openapi-typescript-code-generator/templates";

  3. Templates.ClassApiClient.generator;
  4. Templates.FunctionalApiClient.generator;
  5. Templates.CurryingFunctionalApiClient.generator;
  6. ```

Templates.ClassApiClient.generator


We provide a class-based API client. Please inject the API client dependency and use it instead of constructor.

  1. ``` ts
  2. export interface RequestArgs {
  3.   httpMethod: HttpMethod;
  4.   url: string;
  5.   headers: ObjectLike | any;
  6.   requestBody?: ObjectLike | any;
  7.   requestBodyEncoding?: Record<string, Encoding>;
  8.   queryParameters?: QueryParameters | undefined;
  9. }

  10. export interface ApiClient<RequestOption> {
  11.   request: <T = SuccessResponses>(requestArgs: RequestArgs, options?: RequestOption) => Promise<T>;
  12. }

  13. export class Client<RequestOption> {
  14.   private baseUrl: string;
  15.   constructor(private apiClient: ApiClient<RequestOption>, baseUrl: string) {
  16.     this.baseUrl = baseUrl.replace(/\/$/, "");
  17.   }

  18.   public async createPublisherV2<RequestContentType extends RequestContentType$createPublisherV2>(
  19.     params: Params$createPublisherV2<RequestContentType>,
  20.     option?: RequestOption,
  21.   ): Promise<Response$createPublisherV2$Status$200["application/json"]> {
  22.     const url = this.baseUrl + `/create/v2/publisher/{id}`;
  23.     const headers = {
  24.       "Content-Type": params.headers["Content-Type"],
  25.       Accept: "application/json",
  26.     };
  27.     const requestEncodings = {
  28.       "application/x-www-form-urlencoded": {
  29.         color: {
  30.           style: "form",
  31.           explode: false,
  32.         },
  33.       },
  34.       "application/json": {
  35.         color: {
  36.           style: "form",
  37.           explode: false,
  38.         },
  39.       },
  40.     };
  41.     return this.apiClient.request(
  42.       {
  43.         httpMethod: "POST",
  44.         url,
  45.         headers,
  46.         requestBody: params.requestBody,
  47.         requestBodyEncoding: requestEncodings[params.headers["Content-Type"]],
  48.       },
  49.       option,
  50.     );
  51.   }
  52. }
  53. ```

Templates.FunctionalApiClient.generator


We also provide a function-based API client that replaces the class-based API client with createClient. Please inject the API client dependency and use it.

  1. ``` ts
  2. export interface RequestArgs {
  3.   httpMethod: HttpMethod;
  4.   url: string;
  5.   headers: ObjectLike | any;
  6.   requestBody?: ObjectLike | any;
  7.   requestBodyEncoding?: Record<string, Encoding>;
  8.   queryParameters?: QueryParameters | undefined;
  9. }

  10. export interface ApiClient<RequestOption> {
  11.   request: <T = SuccessResponses>(requestArgs: RequestArgs, options?: RequestOption) => Promise<T>;
  12. }

  13. export const createClient = <RequestOption>(apiClient: ApiClient<RequestOption>, baseUrl: string) => {
  14.   const _baseUrl = baseUrl.replace(/\/$/, "");
  15.   return {
  16.     createPublisherV2: <RequestContentType extends RequestContentType$createPublisherV2>(
  17.       params: Params$createPublisherV2<RequestContentType>,
  18.       option?: RequestOption,
  19.     ): Promise<Response$createPublisherV2$Status$200["application/json"]> => {
  20.       const url = _baseUrl + `/create/v2/publisher/{id}`;
  21.       const headers = {
  22.         "Content-Type": params.headers["Content-Type"],
  23.         Accept: "application/json",
  24.       };
  25.       const requestEncodings = {
  26.         "application/x-www-form-urlencoded": {
  27.           color: {
  28.             style: "form",
  29.             explode: false,
  30.           },
  31.         },
  32.         "application/json": {
  33.           color: {
  34.             style: "form",
  35.             explode: false,
  36.           },
  37.         },
  38.       };
  39.       return apiClient.request(
  40.         {
  41.           httpMethod: "POST",
  42.           url,
  43.           headers,
  44.           requestBody: params.requestBody,
  45.           requestBodyEncoding: requestEncodings[params.headers["Content-Type"]],
  46.         },
  47.         option,
  48.       );
  49.     },
  50.   };
  51. };
  52. ```

Templates.CurryingFunctionalApiClient.generator


Tree shaking support

We also provide a curried function-based API client that requires injection of API client for each operationId. The first function argument demands ApiClient while the second function argument demands RequestArgs. The ApiClient interface is different from the others, as it requires uri as an argument.

This is designed for use cases that utilize tree shaking.

  1. ``` ts
  2. export interface RequestArgs {
  3.   httpMethod: HttpMethod;
  4.   uri: string; // <------------------ Note that the uri
  5.   headers: ObjectLike | any;
  6.   requestBody?: ObjectLike | any;
  7.   requestBodyEncoding?: Record<string, Encoding>;
  8.   queryParameters?: QueryParameters | undefined;
  9. }
  10. export interface ApiClient<RequestOption> {
  11.   request: <T = SuccessResponses>(requestArgs: RequestArgs, options?: RequestOption) => Promise<T>;
  12. }
  13. export const createPublisherV2 =
  14.   <RequestOption>(apiClient: ApiClient<RequestOption>) =>
  15.   <RequestContentType extends RequestContentType$createPublisherV2>(
  16.     params: Params$createPublisherV2<RequestContentType>,
  17.     option?: RequestOption,
  18.   ): Promise<Response$createPublisherV2$Status$200["application/json"]> => {
  19.     const uri = `/create/v2/publisher/{id}`;
  20.     const headers = {
  21.       "Content-Type": params.headers["Content-Type"],
  22.       Accept: "application/json",
  23.     };
  24.     const requestEncodings = {
  25.       "application/x-www-form-urlencoded": {
  26.         color: {
  27.           style: "form",
  28.           explode: false,
  29.         },
  30.       },
  31.       "application/json": {
  32.         color: {
  33.           style: "form",
  34.           explode: false,
  35.         },
  36.       },
  37.     };
  38.     return apiClient.request(
  39.       {
  40.         httpMethod: "POST",
  41.         uri,
  42.         headers,
  43.         requestBody: params.requestBody,
  44.         requestBodyEncoding: requestEncodings[params.headers["Content-Type"]],
  45.       },
  46.       option,
  47.     );
  48.   };
  49. ```

Split the type definition file and the API Client implementation


  1. ``` ts
  2. import * as fs from "fs";

  3. import { CodeGenerator } from "@himenon/openapi-typescript-code-generator";
  4. import * as Templates from "@himenon/openapi-typescript-code-generator/templates";
  5. import type * as Types from "@himenon/openapi-typescript-code-generator/types";

  6. const main = () => {
  7.   const codeGenerator = new CodeGenerator("your/openapi/spec.yml");

  8.   const apiClientGeneratorTemplate: Types.CodeGenerator.CustomGenerator<Templates.FunctionalApiClient.Option> = {
  9.     generator: Templates.FunctionalApiClient.generator,
  10.     option: {},
  11.   };

  12.   const typeDefCode = codeGenerator.generateTypeDefinition();
  13.   const apiClientCode = codeGenerator.generateCode([
  14.     {
  15.       generator: () => {
  16.         return [`import { Schemas, Responses } from "./types";`];
  17.       },
  18.     },
  19.     codeGenerator.getAdditionalTypeDefinitionCustomCodeGenerator(),
  20.     apiClientGeneratorTemplate,
  21.   ]);

  22.   fs.writeFileSync("types.ts", typeDefCode, { encoding: "utf-8" });
  23.   fs.writeFileSync("apiClient.ts", apiClientCode, { encoding: "utf-8" });
  24. };

  25. main();
  26. ```

Create a Code Template


The examples in this section can be used in the following ways

  1. ``` ts
  2. import * as fs from "fs";

  3. import { CodeGenerator } from "@himenon/openapi-typescript-code-generator";
  4. import type * as Types from "@himenon/openapi-typescript-code-generator/types";

  5. /** Write the definition of the Code Template here. */
  6. const customGenerator: Types.CodeGenerator.CustomGenerator<{}> = {
  7.   /** .... */
  8. };

  9. const codeGenerator = new CodeGenerator("your/openapi/spec.yml");

  10. const code = codeGenerator.generateCode([customGenerator]);

  11. fs.writeFileSync("output/file/name", code, { encoding: "utf-8" });
  12. ```

Define a text-based code template


A self-defined code generator can return an array of string.

  1. ``` ts
  2. import * as Types from "@himenon/openapi-typescript-code-generator/types";

  3. interface Option {
  4.   showLog?: boolean;
  5. }

  6. const generator: Types.CodeGenerator.GenerateFunction<Option> = (payload: Types.CodeGenerator.Params[], option): string[] => {
  7.   if (option && option.showLog) {
  8.     console.log("show log message");
  9.   }
  10.   return ["Hello world"];
  11. };

  12. const customGenerator: Types.CodeGenerator.CustomGenerator<Option> = {
  13.   generator: generator,
  14.   option: {},
  15. };
  16. ```

Define using the information extracted from OpenAPI Schema


The self-defined code generator can accept parameters extracted from OpenAPI Schema. See Type definitions for available parameters.

  1. ``` ts
  2. import * as Types from "@himenon/openapi-typescript-code-generator/types";

  3. interface Option {}

  4. const generator: Types.CodeGenerator.GenerateFunction<Option> = (payload: Types.CodeGenerator.Params[], option): string[] => {
  5.   return payload.map(params => {
  6.     return `function ${params.operationId}() { console.log("${params.comment}") }`;
  7.   });
  8. };

  9. const customGenerator: Types.CodeGenerator.CustomGenerator<Option> = {
  10.   generator: generator,
  11.   option: {},
  12. };
  13. ```

Define any Data Types Format


Convert a Data Type with the following format to any type definition.

  1. ``` yaml
  2. components:
  3.   schemas:
  4.     Binary:
  5.       type: string
  6.       format: binary
  7.     IntOrString:
  8.       type: string
  9.       format: int-or-string
  10.     AandB:
  11.       type: string
  12.       format: A-and-B
  13. ```

The option to convert the Data Type Format to an arbitrary type definition is defined as follows.

  1. ``` ts
  2. import { CodeGenerator, Option } from "@himenon/openapi-typescript-code-generator";
  3. const option: Option = {
  4.   convertOption: {
  5.     formatConversions: [
  6.       {
  7.         selector: {
  8.           format: "binary",
  9.         },
  10.         output: {
  11.           type: ["Blob"],
  12.         },
  13.       },
  14.       {
  15.         selector: {
  16.           format: "int-or-string",
  17.         },
  18.         output: {
  19.           type: ["number", "string"],
  20.         },
  21.       },
  22.       {
  23.         selector: {
  24.           format: "A-and-B",
  25.         },
  26.         output: {
  27.           type: ["A", "B"],
  28.           multiType: "allOf",
  29.         },
  30.       },
  31.     ],
  32.   },
  33. };
  34. const codeGenerator = new CodeGenerator(inputFilename, option);
  35. ```

The typedef generated by this will look like this

  1. ``` ts
  2. export namespace Schemas {
  3.   export type Binary = Blob;
  4.   export type IntOrString = number | string;
  5.   export type AandB = A & B;
  6. }
  7. ```

Define a code template with TypeScript AST


You can extend your code using the API of TypeScript AST. You can directly use the API of TypeScript AST or use the wrapper API of TypeScript AST provided by this library.

  1. ``` ts
  2. import * as Types from "@himenon/openapi-typescript-code-generator/types";
  3. import { TsGenerator } from "@himenon/openapi-typescript-code-generator/api";

  4. interface Option {}

  5. const factory = TsGenerator.Factory.create();

  6. const generator: Types.CodeGenerator.GenerateFunction<Option> = (
  7.   payload: Types.CodeGenerator.Params[],
  8.   option,
  9. ): Types.CodeGenerator.IntermediateCode[] => {
  10.   return payload.map(params => {
  11.     return factory.InterfaceDeclaration.create({
  12.       export: true,
  13.       name: params.functionName,
  14.       members: [],
  15.     });
  16.   });
  17. };

  18. const customGenerator: Types.CodeGenerator.CustomGenerator<Option> = {
  19.   generator: generator,
  20.   option: {},
  21. };
  22. ```

API


CodeGenerator


  1. ``` ts
  2. import { CodeGenerator } from "@himenon/openapi-typescript-code-generator";
  3. ```

validateOpenApiSchema


Performs validation of the input OpenAPI Schema.

generateTypeDefinition


Generates code that converts OpenAPI Schema to TypeScript type definitions.

generateCode


You can specify several of your own code generators, and the generators can use parameters extracted from OpenAPI Schema. It internally performs the conversion of an array of string or ts.Statement as a string.

For example, creating a generator in units of file divisions increases the reusability of the generator.

getCodeGeneratorParamsArray


It provides parameters extracted from OpenAPI Schema.

getAdditionalTypeDefinitionCustomCodeGenerator


This is a type definition file for Templates.FunctionalApiClient. The reason it is not included in generateTypeDefinition is that you may not use the type definition generated by this function depending on your usage.

※ The reason it is not included in generateTypeDefinition is that you may not use the type definitions generated by this function depending on your application.

TsGenerator


  1. ``` ts
  2. import { TsGenerator } from "@himenon/openapi-typescript-code-generator/api";
  3. ```

This is a wrapper API for the TypeScript AST used internally. It is subject to change without notice.

OpenApiTools


  1. ``` ts
  2. import { OpenApiTools } from "@himenon/openapi-typescript-code-generator/api";
  3. ```

Parser


OpenApiTools.Parser

This is the API for parsing OpenAPI Schema. It is subject to change without notice.

Restrictions


Directory Restrictions for Remote Reference


There is a limitation on the directory structure supported. To simplify implementation when converting directory structures to TypeScript namespaces, Remote References using $ref should only be defined in the following directory structures. If you want to extend i
Last Updated: 2023-09-03 17:10:52