Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/toomuchdesign/openapi-ts-json-schema

OpenAPI ➡️ TypeScript JSON Schema generator.
https://github.com/toomuchdesign/openapi-ts-json-schema

generator json-schema openapi swagger typescript

Last synced: 21 days ago
JSON representation

OpenAPI ➡️ TypeScript JSON Schema generator.

Awesome Lists containing this project

README

        

# openapi-ts-json-schema

[![Build Status][ci-badge]][ci]
[![Npm version][npm-version-badge]][npm]
[![Coveralls][coveralls-badge]][coveralls]

Generate **TypeScript JSON schema** files (`.ts` modules with `as const` assertions) from **OpenAPI** definitions.

**TypeScript JSON schemas** are 100% valid JSON schemas which serve as the single source of truth for runtime validation and data type inference.

TypeScript JSON schemas serve various purposes, including:

- Validate data and infer validated data TS types with the same JSON schema (with any JSON schema validator like [Ajv](https://ajv.js.org/))
- Infer TS type definitions from JSON schemas (with [`json-schema-to-ts`](https://github.com/ThomasAribart/json-schema-to-ts))
- Fastify integration: infer route handlers input types from their schema (with [`@fastify/type-provider-json-schema-to-ts`](https://github.com/fastify/fastify-type-provider-json-schema-to-ts))

Given an OpenAPI definition file, `openapi-ts-json-schema` will:

- Resolve external/remote `$ref`s and dereference them with [`@apidevtools/json-schema-ref-parser`](https://github.com/APIDevTools/json-schema-ref-parser)
- Optionally inline, import or retain local `$ref`s
- Convert to JSON schema with [`@openapi-contrib/openapi-schema-to-json-schema`](https://github.com/openapi-contrib/openapi-schema-to-json-schema) and [`openapi-jsonschema-parameters`](https://www.npmjs.com/package/openapi-jsonschema-parameters)
- Generate a TypeScript JSON schema file for each definition (`.ts` files with `as const` assertion)
- Organizing schemas in a folder structure mirroring the original OpenAPI definition layout.

`openapi-ts-json-schema` is currently in v0, which means it's still in its testing phase. I'm actively collecting feedback from users to improve its functionality and usability. **Please don't hesitate to open an issue if you encounter any problems or issues while using it.**

## Installation

```
npm i openapi-ts-json-schema -D
```

## Usage

Generate your TypeScript JSON schemas:

```ts
import { openapiToTsJsonSchema } from 'openapi-ts-json-schema';

const { outputPath } = await openapiToTsJsonSchema({
openApiSchema: 'path/to/open-api-specs.yaml',
definitionPathsToGenerateFrom: ['paths', 'components.schemas'],
});
```

...and use them in your TS project:

```ts
import Ajv from 'ajv';
import type { FromSchema } from 'json-schema-to-ts';
import mySchema from 'path/to/generated/schemas/MyModel.ts';

const ajv = new Ajv();
// Perform data validation and type inference using the same schema
const validate = ajv.compile>(mySchema);
const data: unknown = {};

if (validate(data)) {
// data gets type inference
console.log(data.foo);
} else {
console.log(validate.errors);
}
```

## Options

| Property | Type | Description | Default |
| ---------------------------------------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| **openApiSchema** _(required)_ | `string` | Path to the OpenApi file (supports yaml and json). | - |
| **definitionPathsToGenerateFrom** _(required)_ | `string[]` | OpenApi definition object paths to generate the JSON schemas from. Only matching paths will be generated. Supports dot notation: `["components.schemas"]`. | - |
| **refHandling** | `"import" \| "inline" \| "keep"` | `"import"`: generate and import `$ref` schemas.
`"inline"`: inline `$ref` schemas.
`"keep"`: keep `$ref` values. | `"import"` |
| **$idMapper** | `(params: { id: string }) => string` | Customize generated schemas `$id`s and `$ref`s | - |
| **schemaPatcher** | `(params: { schema: JSONSchema }) => void` | Dynamically patch generated JSON schemas. The provided function will be invoked against every single JSON schema node. | - |
| **outputPath** | `string` | Path where the generated schemas will be saved. Defaults to `/schemas-autogenerated` in the same directory of `openApiSchema`. | - |
| **plugins** | `ReturnType[]` | A set of optional plugins to generate extra custom output. See [plugins docs](./docs/plugins.md). | - |
| **silent** | `boolean` | Don't log user messages. | `false` |

## Notes

Take a look at the [Developer's notes](./docs/developer-notes.md) for a few more in-depth explanations.

### `$ref`s handling

`openapi-ts-json-schema` provides 3 `refHandling` strategies for OpenAPI `$ref` properties:

| `refHandling` option | |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `inline` | Replaces `$ref`s with inline copies of the target definition, creating self-contained schemas with potential redundancy |
| `import` | Replaces `$ref`s with a local variable pointing to the module of the target `$ref` definition |
| `keep` | Retains `$ref`s values without modification |

`inline` and `import` are the more straightforward options, producing outputs that can be readily interpreted and resolved by both JavaScript engines and TypeScript type checkers. Nevertheless, a downside of these approaches is the absence of `$ref` references, causing entities initially designed as shareable (`$ref`-able) components (e.g. `components/schemas/Foo`) to lose their recognizability.

A significant limitation arises from consumer applications being unable to automatically expose an OpenAPI schema with proper shared `components/schemas` definitions, as everything becomes inlined.

One potential solution involves preserving `$ref`s using the `keep` option and crafting a plugin (as discussed in the [Plugins](#plugins) section) to facilitate the interpretation of `$ref` information by JavaScript and TypeScript. The implementation logic of this plugin hinges on the framework through which the generated schemas will be consumed.

`openapi-ts-json-schema` ships with a [`fastify` plugin](/docs/plugins.md) available out of the box, enabling seamless integration of schema types through [json-schema-to-ts](https://github.com/ThomasAribart/json-schema-to-ts).

#### Circular `$ref`s

Circular `$ref`s references are supported, too:

| `refHandling` option | |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `inline` | Nested circular references are replaced with `{}` |
| `import` | Completely resolves the JSON schema tree. However, the TypeScript engine will halt type recursion and assign the schema type as `any`, resulting in error `ts(7022)` |
| `keep` | Does not resolve circular references by definition |

For further details, refer to the [relevant tests](https://github.com/toomuchdesign/openapi-ts-json-schema/blob/master/test/circularReference.test.ts).

## Return values

Beside generating the expected schema files under `outputPath`, `openapiToTsJsonSchema` returns the following meta data:

```ts
{
// The path where the schemas are generated
outputPath: string;
metaData: {
// Meta data of the generated schemas
schemas: Map<
// Schema internal id. Eg: "/components/schemas/MySchema"
string,
{
id: string;
// Internal unique schema identifier. Eg `"/components/schemas/MySchema"`
$id: string;
// JSON schema Compound Schema Document `$id`. Eg: `"/components/schemas/MySchema"`
uniqueName: string;
// Unique JavaScript identifier used as import name. Eg: `"componentsSchemasMySchema"`
openApiDefinition: OpenApiObject;
// Original dereferenced openAPI definition
originalSchema: JSONSchema | string;
// Original dereferenced JSON schema
isRef: boolean;
// True if schemas is used as a `$ref`
shouldBeGenerated: boolean;
// True is the schema has to be generated

absoluteDirName: string;
// Absolute path pointing to schema folder (posix or win32). Eg: `"Users/username/output/path/components/schemas"`
absolutePath: string;
// Absolute path pointing to schema file (posix or win32). Eg: `"Users/username/output/path/components/schemas/MySchema.ts"`
absoluteImportPath: string;
// Absolute import path (posix or win32, without extension). Eg: `"Users/username/output/path/components/schemas/MySchema"`
}
>;
}
}
```

## Plugins

Plugins are intended as a way to generate extra artifacts based on the same internal metadata created to generate the JSON schema output.

`openapi-ts-json-schema` currently ships with one plugin specifically designed to better integrate with [Fastify](https://fastify.dev/), but you can write your own!

Read [plugins documentation 📖](./docs/plugins.md).

## Todo

- Consider removing required `definitionPathsToGenerateFrom` option in favour of exporting the whole OpenAPI definitions based on the structure defined in specs
- Improve external `#ref`s handling (currently being inlined and duplicated)
- Find a way to merge multiple different OpenApi definitions consistently
- Consider implementing an option to inline circular $refs with a configurable nesting level
- Handle `$ref` parameters according to `refHandler` options
- Rename `openApiSchema` --> `OpenApiDocument`

[ci-badge]: https://github.com/toomuchdesign/openapi-ts-json-schema/actions/workflows/ci.yml/badge.svg
[ci]: https://github.com/toomuchdesign/openapi-ts-json-schema/actions/workflows/ci.yml
[coveralls-badge]: https://coveralls.io/repos/github/toomuchdesign/openapi-ts-json-schema/badge.svg?branch=master
[coveralls]: https://coveralls.io/github/toomuchdesign/openapi-ts-json-schema?branch=master
[npm]: https://www.npmjs.com/package/openapi-ts-json-schema
[npm-version-badge]: https://img.shields.io/npm/v/openapi-ts-json-schema.svg