Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

openapi-metadata #1992

Merged
merged 25 commits into from
Nov 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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/" },
kerwanp marked this conversation as resolved.
Show resolved Hide resolved
{ 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