Skip to content

Commit

Permalink
Merge pull request #6 from samchon/features/recursiveRef
Browse files Browse the repository at this point in the history
Memoize `OpenAPI` conversion.
  • Loading branch information
samchon authored Apr 12, 2024
2 parents 7b94f5a + eb0111a commit 47090bd
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 32 deletions.
60 changes: 59 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,64 @@
# `@samchon/openapi`

![Nestia Editor](https://github.com/samchon/openapi/assets/13158709/350128f7-c159-4ba4-8f8c-743908ada8eb)

[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/samchon/openapi/blob/master/LICENSE)
[![npm version](https://img.shields.io/npm/v/@samchon/openapi.svg)](https://www.npmjs.com/package/@samchon/openapi)
[![Downloads](https://img.shields.io/npm/dm/@samchon/openapi.svg)](https://www.npmjs.com/package/@samchon/openapi)
[![Build Status](https://github.com/samchon/openapi/workflows/build/badge.svg)](https://github.com/samchon/openapi/actions?query=workflow%3Abuild)

OpenAPI definitions and converters for [typia](https://github.com/samchon/typia) and [nestia](https://github.com/samchon/nestia).
OpenAPI definitions and converters for [typia](https://github.com/samchon/typia) and [nestia](https://github.com/samchon/nestia).

`@samchon/openapi` is a collection of OpenAPI definitions of below versions. Those type definitions does not contain every properties of OpenAPI specification, but just have only some features essentially required for `typia` and `nestia` (especially [`@nestia/editor`](https://nestia.io/docs/editor/)).

1. [Swagger v2.0](https://github.com/samchon/openapi/blob/master/src/SwaggerV2.ts)
2. [OpenAPI v3.0](https://github.com/samchon/openapi/blob/master/src/OpenApiV3.ts)
3. [OpenAPI v3.1](https://github.com/samchon/openapi/blob/master/src/OpenApiV3_1.ts)

Also, `@samchon/openapi` provides emended OpenAPI v3.1 definition and its converter from above versions for convenient development. The keyword "emended" means that [`OpenApi`](https://github.com/samchon/openapi/blob/master/src/OpenApi.ts) is not a direct OpenAPI v3.1 specification (OpenApiV3_1), but a little bit shrinked to remove ambiguous and duplicated expressions of OpenAPI v3.1 for the convenience of typia and nestia

For example, when representing nullable type, OpenAPI v3.1 supports three ways. In that case, OpenApi remains only the third way, so that makes `typia` and `nestia` (especially [`@nestia/editor`](https://nestia.io/docs/editor/)) to be simple and easy to implement.

- `{ type: ["string", "null"] }`
- `{ type: "string", nullable: true }`
- `{ oneOf: [{ type: "string" }, { type: "null" }] }`

Here is the entire list of differences between OpenAPI v3.1 and emended OpenApi.

- Operation
- Merged `OpenApiV3_1.IPathItem.parameters` to `OpenApi.IOperation.parameters`
- Resolved references of `OpenApiV3_1.IOperation` mebers
- JSON Schema
- Decomposed mixed type: `OpenApiV3_1.IJsonSchema.IMixed`
- Resolved nullable property: `OpenApiV3_1.IJsonSchema.__ISignificant.nullable`
- Array type utilizes only single `OpenAPI.IJsonSchema.IArray.items`
- Tuple type utilizes only `OpenApi.IJsonSchema.ITuple.prefixItems`
- Merged `OpenApiV3_1.IJsonSchema.IAnyOf` to `OpenApi.IJsonSchema.IOneOf`
- Merged `OpenApiV3_1.IJsonSchema.IRecursiveReference` to `OpenApi.IJsonSchema.IReference`



## How to use
```bash
npm install @samchon/openapi
```

```typescript
import { OpenApi, SwaggerV2, OpenApiV3, OpenApiV3_1 } from "@samchon/openapi";

// original Swagger/OpenAPI document
const input:
| SwaggerV2.IDocument
| OpenApiV3.IDocument
| OpenApiV3_1.IDocument = { ... };

// you can convert it to emended OpenAPI v3.1
const output: OpenApi.IDocument = OpenApi.convert(input);
```



## Related Projects
- `typia`: https://github.com/samchon/typia
- `nestia`: https://github.com/samchon/nestia
- `@nestia/editor`: https://nestia.io/docs/editor
23 changes: 18 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@samchon/openapi",
"version": "0.1.4",
"description": "",
"version": "0.1.5",
"description": "OpenAPI definitions and converters for 'typia' and 'nestia'.",
"main": "./lib/index.js",
"typings": "./lib/index.d.ts",
"scripts": {
Expand All @@ -12,9 +12,22 @@
"dev": "npm run build:test -- --watch",
"test": "node bin/test"
},
"keywords": [],
"author": "",
"license": "ISC",
"keywords": [
"swagger",
"openapi",
"typia",
"nestia"
],
"repository": {
"type": "git",
"url": "https://github.com/samchon/openapi"
},
"author": "Jeongho Nam",
"license": "MIT",
"bugs": {
"url": "https://github.com/samchon/openapi/issues"
},
"homepage": "https://github.com/samchon/openapi",
"devDependencies": {
"@types/node": "^20.12.7",
"prettier": "^3.2.5",
Expand Down
7 changes: 4 additions & 3 deletions src/OpenApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import { SwaggerV2Converter } from "./internal/SwaggerV2Converter";
* In that case, `OpenApi` remains only the third way, so that makes `typia` and
* `nestia` (especially `@nestia/editor`) to be simple and easy to implement.
*
* 1. `type: ["string", "null"]`
* 2. `type: "string", nullable: true`
* 3. `oneOf: [{ type: "string" }, { type: "null" }]`
* 1. `{ type: ["string", "null"] }`
* 2. `{ type: "string", nullable: true }`
* 3. `{ oneOf: [{ type: "string" }, { type: "null" }] }`
*
* Here is the entire list of differences between OpenAPI v3.1 and emended `OpenApi`.
*
Expand Down Expand Up @@ -78,6 +78,7 @@ export namespace OpenApi {
>;
security?: Record<string, string[]>[];
tags?: IDocument.ITag[];
"x-samchon-emended"?: boolean;
}
export namespace IDocument {
export interface IInfo {
Expand Down
1 change: 1 addition & 0 deletions src/OpenApiV3_1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export namespace OpenApiV3_1 {
>;
security?: Record<string, string[]>[];
tags?: IDocument.ITag[];
"x-samchon-emended"?: boolean;
}
export namespace IDocument {
export interface IInfo {
Expand Down
51 changes: 28 additions & 23 deletions src/internal/OpenApiV3_1Converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,34 @@ import { OpenApi } from "../OpenApi";
import { OpenApiV3_1 } from "../OpenApiV3_1";

export namespace OpenApiV3_1Converter {
export const convert = (input: OpenApiV3_1.IDocument): OpenApi.IDocument => ({
...input,
components: convertComponents(input.components ?? {}),
paths: input.paths
? Object.fromEntries(
Object.entries(input.paths)
.filter(([_, v]) => v !== undefined)
.map(
([key, value]) => [key, convertPathItem(input)(value)] as const,
),
)
: undefined,
webhooks: input.webhooks
? Object.fromEntries(
Object.entries(input.webhooks)
.filter(([_, v]) => v !== undefined)
.map(
([key, value]) => [key, convertWebhooks(input)(value)!] as const,
)
.filter(([_, value]) => value !== undefined),
)
: undefined,
});
export const convert = (input: OpenApiV3_1.IDocument): OpenApi.IDocument => {
if (input["x-samchon-emended"] === true) return input as OpenApi.IDocument;
return {
...input,
components: convertComponents(input.components ?? {}),
paths: input.paths
? Object.fromEntries(
Object.entries(input.paths)
.filter(([_, v]) => v !== undefined)
.map(
([key, value]) => [key, convertPathItem(input)(value)] as const,
),
)
: undefined,
webhooks: input.webhooks
? Object.fromEntries(
Object.entries(input.webhooks)
.filter(([_, v]) => v !== undefined)
.map(
([key, value]) =>
[key, convertWebhooks(input)(value)!] as const,
)
.filter(([_, value]) => value !== undefined),
)
: undefined,
"x-samchon-emended": true,
};
};

/* -----------------------------------------------------------
OPERATORS
Expand Down

0 comments on commit 47090bd

Please sign in to comment.