Skip to content

nfroidure/openapi-ts-sdk-builder

openapi-ts-sdk-builder

Create a TypeScript SDK from an OpenAPI 3 definition

GitHub license

A TypeScript rewrite of openapi-js-sdk-builder.

It basically brings a minimal TypeScript SDK from an OpenAPI3 file with no OOP inside. It works with any HTTP client.

Usage

With a raw Node script:

import { generateSDKFromOpenAPI } from 'openapi-ts-sdk-builder'; import { readFileSync, writeFileSync } from 'fs'; const openAPIContents = readFileSync('openapi.json', 'utf-8'); const sdkContents = generateSDKFromOpenAPI( openAPIContents, { sdkVersion: 'v1.1.1', ignoredParametersNames: ['cookie', 'X-API-Version', 'X-SDK-Version'], undocumentedParametersNames: ['X-Application-Version'], }, { generateUnusedSchemas: true, brandedTypes: [ 'SensorUUID', 'UUID', 'Locale', 'TimeZone', 'ValueName', 'SensorVariable', ], generateRealEnums: true, exportNamespaces: true, }, ); writeFileSync('src/sdk.ts', sdkContents, 'utf-8');

Sample usage with axios:

import BaseAPI, { APIStatuses } from './sdk.ts'; import axios from 'axios'; import querystring from 'querystring'; import type { RequestExecutor } from './sdk.ts'; import type { AxiosRequestConfig } from 'axios'; const executeRequest: RequestExecutor<AxiosRequestConfig> = async ( httpRequest, operationId, options, ) => { const callOptions = { ...options, baseURL: 'http://localhost:3000', url: httpRequest.path, method: httpRequest.method, headers: { ...(options.headers || {}), ...(httpRequest.headers || {}), }, params: httpRequest.params, data: httpRequest.body, paramsSerializer: querystring.stringify.bind(querystring), validateStatus: (status: number) => APIStatuses[operationId].includes(status), }; const response = await axios(callOptions); return { status: response.status, headers: response.headers, body: response.data, }; }; // Use the API await BaseAPI.getPing(executeRequest); await BaseAPI.getUser(executeRequest, { userId: '123' }); // Generate URIs only use the API then await APIURIBuilders.buildGetPingURI({ /*...*/ }); // To know which method is used by an endpoint APIMethods.getPing; // => get // To know which status codes can be returned by an endpoint APIStatuses.getPing; // => ["default", 200] // Generate a complete endpoint input // (may be useful when you want to pass // HTTP requests to another process ) APIInputBuilders.buildGetPingInput({ /*...*/ });

You can also safely operate on the API by doing so:

import BaseAPI, { APIStatuses } from './sdk.ts'; import config from './config'; import YError from 'yerror'; import type { RequestExecutor, Components } from './sdk.ts'; import type { AxiosRequestConfig } from 'axios'; export { Enums }; export type { Components }; type AuthTokenInput = { token?: string }; const API = Object.keys(BaseAPI).reduce((FinalAPI, operationId) => { FinalAPI[operationId] = async ( { token, ...input }: unknown & AuthTokenInput, options: AxiosRequestConfig = {}, ) => { try { const response = await BaseAPI[operationId]( executeRequest, { ...input, xApplicationVersion: config.applicationVersion, }, { ...options, baseURL: config.apiURL, headers: { ...options.headers, ...(token ? { authorization: `Bearer ${token}`, } : {}), }, }, ); return response; } catch (err) { console.error('Got an API error:', err.stack); throw new YError( err.response?.data?.error ? 'E_API_ERROR' : 'E_UNEXPECTED_ERROR', err.response?.data, ); } }; return FinalAPI; }, {}) as { [P in keyof typeof BaseAPI]: ( input: Parameters<typeof BaseAPI[P]>[1] & AuthTokenInput, config?: AxiosRequestConfig, ) => Promise<ReturnType<typeof BaseAPI[P]>>; }; export default API;

Finally, you may appreciate using it with the useSSR React hook to benefit from your SDK types:

import useSWR from 'swr'; import API from './api'; type Handler<I, O> = (input: I) => Promise<O>; type HandlerInput<T> = T extends Handler<infer I, unknown> ? I : never; type HandlerOutput<T> = T extends Handler<unknown, infer I> ? I : never; const API_KEYS: Record<any, string> = Object.keys(API).reduce((hash, key) => { hash[API[key]] = key; return hash; }, {}); export default function useAPISWR<T extends Handler<any, any>>( swrCouple: [T, HandlerInput<T>], options?: Parameters<typeof useSWR>[2], ) { const uniqueKey = swrCouple ? Object.keys(swrCouple[1]).reduce( (finalKey, key) => finalKey + key + JSON.stringify(swrCouple[1][key]), // Sadly, here, we cannot rely on `swrCouple[0].name` to // build the unicity key since the build destroys it API_KEYS[swrCouple[0]] + '-', ) : null; return useSWR< Awaited<HandlerOutput<T>> extends { body: infer D } ? D : never >( uniqueKey, async () => (await swrCouple[0](swrCouple[1])).body, options as any, ); }

API

openapi-ts-sdk-builder

openapi-ts-sdk-builder~generateSDKFromOpenAPI(openAPIContent, options, [typeOptions]) ⇒ Promise.<string>

Build a JS SDK from an OpenAPI file

Kind: inner method of openapi-ts-sdk-builder
Returns: Promise.<string> - The SDK JS code

Param Type Description
openAPIContent string
options Object
options.sdkVersion string The SDK version
[options.sdkName] string The SDK name (default to API)
[options.ignoredParametersNames] Array.<string> Provide a list of parameters to ignore
[options.undocumentedParametersNames] Array.<string> Provide a list of parameters to keep undocumented
[typeOptions] Object Options to be passed to the type generator

Authors

License

MIT

About

Create a TypeScript SDK from an OpenAPI 3 definition

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Sponsor this project

 

Packages

 
 
 

Contributors