Skip to content

Commit

Permalink
openapi-metadata (#1992)
Browse files Browse the repository at this point in the history
  • Loading branch information
kerwanp authored Nov 10, 2024
1 parent 7971500 commit 09624c3
Show file tree
Hide file tree
Showing 71 changed files with 2,447 additions and 14 deletions.
5 changes: 5 additions & 0 deletions .changeset/strange-nails-jam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"openapi-metadata": patch
---

Inititial release
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.DS_Store
dist
node_modules
coverage

packages/openapi-typescript/test/fixtures/cli-outputs/out

Expand Down
36 changes: 31 additions & 5 deletions docs/.vitepress/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,19 @@ export default defineConfig({
},
{
text: "openapi-react-query",
base: "/openapi-react-query",
items: [
{ text: "Getting Started", link: "/openapi-react-query/" },
{ text: "useQuery", link: "/openapi-react-query/use-query" },
{ text: "useMutation", link: "/openapi-react-query/use-mutation" },
{ text: "useSuspenseQuery", link: "/openapi-react-query/use-suspense-query" },
{ text: "queryOptions", link: "/openapi-react-query/query-options" },
{ text: "Getting Started", link: "/" },
{ text: "useQuery", link: "/use-query" },
{ text: "useMutation", link: "/use-mutation" },
{
text: "useSuspenseQuery",
link: "/use-suspense-query",
},
{
text: "queryOptions",
link: "/query-options",
},
{ text: "About", link: "/openapi-react-query/about" },
],
},
Expand All @@ -93,6 +100,19 @@ export default defineConfig({
{ text: "About", link: "/about" },
],
},
{
text: "openapi-metadata",
base: "/openapi-metadata",
items: [
{ text: "Getting Started", link: "/" },
{ text: "Decorators", link: "/decorators" },
{ text: "Metadata", link: "/metadata" },
{ text: "Type loader", link: "/type-loader" },
{ text: "UI Integrations", link: "/ui" },
{ text: "Examples", link: "/examples" },
{ text: "About", link: "/about" },
],
},
],
},
search: {
Expand All @@ -103,6 +123,12 @@ export default defineConfig({
indexName: "openapi-ts",
},
},
socialLinks: [
{
icon: "github",
link: "https://github.com/openapi-ts/openapi-typescript",
},
],
footer: {
message:
'Released under the <a href="https://github.com/openapi-ts/openapi-typescript/blob/main/packages/openapi-typescript/LICENSE">MIT License</a>.',
Expand Down
2 changes: 1 addition & 1 deletion docs/data/contributors.json

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions docs/openapi-metadata/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
title: About openapi-metadata
description: openapi-metadata Project Goals, comparisons, and more
---

<script setup>
import { VPTeamMembers } from 'vitepress/theme';
import contributors from '../data/contributors.json';
</script>

# About

## Project Goals

1. Must respect the OpenAPI V3 specification
2. Be extensible and easily integrated inside backend frameworks
3. Be focused around developer experience

## Contributors

This library wouldn’t be possible without all these amazing contributors:

<VPTeamMembers size="small" :members="contributors['openapi-metadata']" />
25 changes: 25 additions & 0 deletions docs/openapi-metadata/decorators.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
title: Decorators
---

# Decorators

Decorators are used to enrich your OpenAPI specifications. They can be applied on a Controller, a Method or a Model. They are all prefixed with `Api`.

> For more information about the decorators, you can directly refer to the [source code](https://github.com/openapi-ts/openapi-typescript/packages/openapi-metadata/src/decorators).
| Decorator | Usage | Description |
| ----------------------- | ------------------- | ------------------------------------------------------------------------ |
| `@ApiBody` | Method | Sets the requestBody of the operation. |
| `@ApiCookie` | Controller / Method | Adds a cookie parameter to the operation(s). |
| `@ApiExcludeController` | Method | Excludes the operations of this controller from the document generation. |
| `@ApiExcludeOperation` | Method | Excludes this operation from the document generation. |
| `@ApiExtraModels` | Controller | Adds extra models to be loaded in the schema. |
| `@ApiHeader` | Controller / Method | Adds a header parameter to the operation(s). |
| `@ApiOperation` | Method | Configures an operation. |
| `@ApiParam` | Controller / Method | Adds a path parameter to the operation(s). |
| `@ApiProperty` | Model | Configures a schema property property. |
| `@ApiQuery` | Controller / Method | Adds a query parameter to the operation(s). |
| `@ApiResponse` | Controller / Method | Adds a response to the operation(s). |
| `@ApiSecurity` | Controller / Method | Sets the security scheme to the operation(s). |
| `@ApiTags` | Controller / Method | Adds tags to the operation(s). |
49 changes: 49 additions & 0 deletions docs/openapi-metadata/examples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
title: Examples
---

# Examples

This library is made to be used through an integration with your favorite framework but you can as well use it directly as a document generator.

## Express

```ts
import express from "express";
import { generateDocument } from "openapi-metadata";
import { generateScalarUI } from "openapi-metadata/ui";

const app = express();

const document = await generateDocument(yourConfiguration);

app.get("/api", async (req, res) => {
res.send(JSON.stringify(document));
});

app.get("/api/docs", (req, res) => {
const ui = generateScalarUI("/api");
res.send(ui);
});
```

## Fastify

```ts
import fastify from "fastify";
import { generateDocument } from "openapi-metadata";
import { generateScalarUI } from "openapi-metadata/ui";

const app = Fastify();

const document = await generateDocument(yourConfiguration);

app.get("/api", async () => {
return document;
});

app.get("/api/docs", () => {
const ui = generateScalarUI("/api");
return ui;
});
```
213 changes: 213 additions & 0 deletions docs/openapi-metadata/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
---
title: "Getting started"
---

# Introduction

`openapi-metadata` is a framework agnostic library to automatically generate OpenAPI schemas and documentation by using Typescript decorators and metadata.

::: code-group

```ts [users_controller.ts]
import { ApiOperation, ApiResponse } from "openapi-metadata/decorators";
import User from "./user";

class UsersController {
@ApiOperation({
method: "get",
pattern: "/users",
summary: "List users"
})
@ApiResponse({ type: [User] })
async list() {
...
}
}
```

```ts [user.ts]
import { ApiProperty } from "openapi-metadata/decorators";

class User {
@ApiProperty()
declare id: number;

@ApiProperty()
declare name: string;

@ApiProperty({ required: false })
declare mobile?: string;
}
```

```ts [index.ts]
import "reflect-metadata";
import { generateDocument } from "openapi-metadata";
import UsersController from "./users_controller";

const document = await generateDocument({
controllers: [UsersController],
document: {
info: {
name: "My Api",
version: "1.0.0",
},
},
});

console.log(document); // <- Your generated OpenAPI specifications
```

:::

- ✅ Fully compliant [OpenAPI V3](https://swagger.io/specification/)
- ✅ Automatic type inference
- ✅ Supports [Scalar](https://scalar.com/), [Swagger UI](https://swagger.io/tools/swagger-ui/) and [Rapidoc](https://rapidocweb.com/)
- ✅ Extensible with custom type loaders
- ✅ Ready to be integrated with your favorite framework

## Getting started

### Setup

Install `openapi-metadata` and `reflect-metadata` using your favorite package manager.

```bash
npm install openapi-metadata reflect-metadata
```

Import `reflect-metadata` in your main file.

::: code-group

```ts [index.ts]
import "reflect-metadata";

// Rest of your app
```

:::

Enable `experimentalDecorators` and `experimentalDecorators`.

::: code-group

```json [tsconfig.json]
{
"compilerOptions": {
"emitDecoratorMetadata": true,
"experimentalDecorators": true
}
}
```

:::

### Create your OpenAPI document

To get started, you can use the `generateDocument` function to create an (almost) empty documentation. You can define a base document that will be merged with the generated one.

::: code-group

```ts [index.ts]
import "reflect-metadata";
import { generateDocument } from "openapi-metadata";

const builder = await generateDocument({
controllers: [],
document: {
info: {
name: "My API",
version: "1.0.0",
},
},
});

console.log(document.build()); // <- Your generated OpenAPI specifications
```

:::

### Create your first controller

A controller is a simple class where each methods could be an Operation.
In the following example we have a `UsersController` which declares an operation `GET /users` that returns a list of `Users`.

::: code-group

```ts [controllers/users_controller.ts]
import { ApiOperation, ApiResponse } from "openapi-metadata/decorators";
import User from "../schemas/user";

export default class UsersController {
@ApiOperation({
method: "get",
pattern: "/users",
summary: "List users",
})
@ApiResponse({ type: [User] })
async list() {
// ...your logic
}
}
```

:::

### Create your first schema

In our controller we define the response of your operation to be `[User]` (a list of users). We now need to create this model.

By using the `@ApiProperty` decorator on class we can define the properties of our schema.

> Unlike other libraries like `@nestjs/swagger`, every element of your OpenAPI schema is lazy-loaded. Your models will only be part of your documentation if it is used.
::: code-group

```ts [schemas/user.ts]
import { ApiProperty } from "openapi-metadata/decorators";

export default class User {
@ApiProperty()
declare id: string;

@ApiProperty({ example: "John Doe" })
declare name: string;

@ApiProperty()
declare email: string;

@ApiProperty({ required: false })
declare mobile?: string;
}
```

:::

### Add the controller to the generated document

Now that we have our controller ready, we can use it to generate our document.

::: code-group

```ts [index.ts]
import "reflect-metadata";
import { generateDocument } from "openapi-metadata";
import UsersController from "./controllers/users_controller.ts";

const builder = await generateDocument({
controllers: [UsersController],
document: {
info: {
name: "My API",
version: "1.0.0",
},
},
});

console.log(document.build()); // <- Your generated OpenAPI specifications
```

:::

### Going further
Loading

0 comments on commit 09624c3

Please sign in to comment.