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

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: about 1 month 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-first JSON Schemas** (`.ts` modules with `as const`) directly from your OpenAPI definitions — so you can use the same schema for both **runtime validation** and **TypeScript type inference**.

## Why?

Keeping **OpenAPI specs**, **runtime validators**, and **TypeScript types** in sync is hard.

Many teams end up maintaining the same api models in different formats:

- JSON Schema for runtime validation (`Ajv`, `Fastify`, etc.)
- TypeScript types for static checking

`openapi-ts-json-schema` solves this by generating **TypeScript JSON Schemas directly from your OpenAPI definitions**: valid JSON schemas written as **TypeScript modules**, ready for runtime validation and type inference.

These schemas:

- ✅ are 100% JSON Schema–compatible (usable with `Ajv`, `Fastify`, etc.)
- ✅ are TypeScript-native (`as const` objects you can import)
- ✅ can be used for type inference via [json-schema-to-ts](https://github.com/ThomasAribart/json-schema-to-ts)
- ✅ are generated automatically from your OpenAPI spec

In short: **OpenAPI spec becomes the single source of truth** for both runtime validation and TypeScript typing.

## Example

From this OpenAPI definition:

```yaml
components:
schemas:
User:
type: object
properties:
id: { type: string }
name: { type: string }
required: [id, name]
```

You get this TypeScript JSON schema:

```ts
// components/schemas/User.ts
export default {
type: 'object',
properties: {
id: { type: 'string' },
name: { type: 'string' },
},
required: ['id', 'name'],
} as const;
```

Now you can use it for both runtime validation and type inference:

```ts
import Ajv from 'ajv';
import type { FromSchema } from 'json-schema-to-ts';

import userSchema from './components/schemas/User';

const ajv = new Ajv();
const validate = ajv.compile>(userSchema);

const data: unknown = {};
if (validate(data)) {
// data is now typed as { id: string; name: string }
} else {
console.error(validate.errors);
}
```

## Installation

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

## Usage

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

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

Schemas are generated in a folder mirroring your OpenAPI layout (default: `schemas-autogenerated`).

### CommonJS

Since `openapi-ts-json-schema` is distributed as an ESM-only package, it must be imported using a dynamic `import()` when used from a CommonJS project:

```ts
async function run() {
const { openapiToTsJsonSchema } = await import('openapi-ts-json-schema');

const { outputPath } = await openapiToTsJsonSchema({
openApiDocument: 'path/to/open-api-specs.yaml',
targets: {
collections: ['components.schemas', 'paths'],
},
moduleSystem: 'cjs',
});
}

run();
```

## Options

### Core options

| Property | Type                                              | Description | Default |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| **openApiDocument** _(required)_ | `string` | Path to an OpenAPI document (JSON or YAML). | - |
| **targets** _(required)_ | `{`` collections?: string[];`` single?: string[];``}` | OpenAPI definition paths to generate JSON Schemas from _(dot notation)_.

`collections`: paths pointing to objects/records of definitions, where each entry will be generated (eg: `["components.schemas"]`).

`single`: paths pointing to individual definitions to generate (eg: `["paths./users/{id}"]`). | - |
| **outputPath** | `string` | Directory where generated schemas will be written. Defaults to `/schemas-autogenerated` in the same directory of `openApiDocument`. | - |
| **refHandling** | `"import" \| "inline" \| "keep"` | `"import"`: generate and import `$ref` schemas.
`"inline"`: inline `$ref` schemas.
`"keep"`: keep `$ref` values. | `"import"` |
| **moduleSystem** | `"cjs" \| "esm"` | Controls how import specifiers are written in generated artifacts. Configure this option based on whether the consuming project is using CommonJS or ECMAScript modules. | `"esm"` |
| **silent** | `boolean` | Don't log user messages. | `false` |

### Advanced options

| Property | Type | Description | Default |
| ----------------- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ------- |
| **idMapper** | `(params: { id: string }) => string` | Customize generated schemas `$id`s and `$ref`s values. Useful for enforcing naming conventions. | - |
| **schemaPatcher** | `(params: { schema: JSONSchema }) => void` | Hook called for every generated schema node, allowing programmatic mutation before output. | - |
| **plugins** | `ReturnType[]` | List of plugins to extend or customize the generation process. See [plugins docs](./docs/plugins.md). | - |

### Full configuration example

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

await openapiToTsJsonSchema({
openApiDocument: './openapi.yaml',
targets: {
collections: ['components.schemas'],
single: ['paths./users/{id}'],
},
outputPath: './generated',
refHandling: 'import',
moduleSystem: 'esm',
silent: false,

idMapper: ({ id }) => id.toUpperCase(),
schemaPatcher: ({ schema }) => {
if (schema.properties && !schema.type) {
schema.type = 'object';
}
},
plugins: [generateSchemaWith$idPlugin()],
});
```

### `refHandling` option

Three strategies for how `$ref`s are resolved:

| `refHandling` option | description |
| -------------------- | ---------------------------------------------------------------------------------------------- |
| `inline` | Inlines `$refs`s, creating self-contained schemas (no imports, but possible redundancy). |
| `import` | Replaces`$ref`s with imports of the target definition |
| `keep` | Leaves `$ref`s untouched — useful if you plan to interpret `$ref`s dynamically or use a plugin |

Circular references are supported:

- `inline`: circular refs are replaced with `{}`
- `import`: resolves the JSON schema but TypeScript recursion halts (`any` type, TS error 7022)
- `keep`: circular refs left unresolved

See [tests](https://github.com/toomuchdesign/openapi-ts-json-schema/blob/master/test/circularReference.test.ts) for details.

## Return values

Along with generated schema files, `openapi-ts-json-schema` returns metadata:

```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;
// Text content of schema file
fileContent?: string;

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

Extend `openapi-ts-json-schema` with custom generators. Currently available plugins:

- `generateSchemaWith$idPlugin`
- `fastifyIntegrationPlugin`

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

## How it works

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

- Resolves and dereferences $refs (using [@apidevtools/json-schema-ref-parser](https://github.com/APIDevTools/json-schema-ref-parser))
- Converts OpenAPI objects to JSON Schema (via [@openapi-contrib/openapi-schema-to-json-schema](https://github.com/APIDevTools/json-schema-ref-parser) & [`openapi-jsonschema-parameters`](https://www.npmjs.com/package/openapi-jsonschema-parameters))
- Generates `.ts` files exporting each schema as `as const`
- Mirrors the original OpenAPI structure in the generated folder
- Supports plugins (e.g. for Fastify integration)

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

## Todo

- 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 `$ref`s with a configurable nesting level

[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