Skip to content

Commit

Permalink
feat(metadata): documentation, fixes and improvements (#2006)
Browse files Browse the repository at this point in the history
* feat(openapi): add comments and improve documentation with twoslash

* feat(metadata): merge properly operations together
  • Loading branch information
kerwanp authored Dec 19, 2024
1 parent 713ea1b commit ca68475
Show file tree
Hide file tree
Showing 45 changed files with 1,163 additions and 84 deletions.
5 changes: 5 additions & 0 deletions .changeset/dry-flies-raise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"openapi-metadata": patch
---

Add comments for better documentation and add new exports
5 changes: 5 additions & 0 deletions .changeset/honest-coats-relax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"openapi-metadata": patch
---

Merge properly operations together
14 changes: 14 additions & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import en from "./en";
import zh from "./zh";
import ja from "./ja";
import shared from "./shared";
import { transformerTwoslash } from "@shikijs/vitepress-twoslash";
import { ModuleKind, ModuleResolutionKind } from "typescript";

// https://vitepress.dev/reference/site-config
export default defineConfig({
Expand All @@ -12,4 +14,16 @@ export default defineConfig({
zh: { label: "简体中文", ...zh },
ja: { label: "日本語", ...ja },
},
markdown: {
codeTransformers: [
transformerTwoslash({
twoslashOptions: {
compilerOptions: {
experimentalDecorators: true,
moduleResolution: ModuleResolutionKind.Bundler,
},
},
}),
],
},
});
24 changes: 16 additions & 8 deletions docs/.vitepress/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,23 @@ export default defineConfig({
},
{
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" },
{ text: "Getting Started", link: "/openapi-metadata" },
{ text: "Decorators", link: "/openapi-metadata/decorators" },
{ text: "Metadata", link: "/openapi-metadata/metadata" },
{ text: "Type loader", link: "/openapi-metadata/type-loader" },
{ text: "UI Integrations", link: "/openapi-metadata/ui" },
{
text: "Integrations",
items: [
{
text: "AdonisJS",
link: "https://friendsofadonis.com/docs/openapi",
},
],
},
{ text: "Examples", link: "/openapi-metadata/examples" },
{ text: "About", link: "/openapi-metadata/about" },
],
},
],
Expand Down
3 changes: 3 additions & 0 deletions docs/.vitepress/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ import type { Theme } from "vitepress";
import DefaultTheme from "vitepress/theme";
import CustomLayout from "./CustomLayout.vue";
import SponsorList from "./SponsorList.vue";
import TwoslashFloatingVue from "@shikijs/vitepress-twoslash/client";
import "./style.css";
import "@shikijs/vitepress-twoslash/style.css";

export default {
extends: DefaultTheme,
Layout: CustomLayout,
enhanceApp({ app, router, siteData }) {
app.component("SponsorList", SponsorList);
app.use(TwoslashFloatingVue);
},
} satisfies Theme;
2 changes: 1 addition & 1 deletion docs/data/contributors.json

Large diffs are not rendered by default.

60 changes: 45 additions & 15 deletions docs/openapi-metadata/decorators.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,48 @@ Decorators are used to enrich your OpenAPI specifications. They can be applied o

> 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). |
_You can hover the following code snippet to get information about each decorator._

```ts twoslash
// @noErrors
// ---cut---
import {
ApiBody,
ApiCookie,
ApiExcludeController,
ApiExcludeOperation,
ApiExtraModels,
ApiHeader,
ApiOperation,
ApiParam,
ApiProperty,
ApiPropertyOptional,
ApiQuery,
ApiResponse,
ApiSecurity,
ApiBasicAuth,
ApiOauth2,
ApiBearerAuth,
ApiCookieAuth,
ApiTags
} from 'openapi-metadata/decorators'
// ---cut---
@ApiBody()
@ApiCookie()
@ApiExcludeController()
@ApiExcludeOperation()
@ApiExtraModels()
@ApiHeader()
@ApiOperation()
@ApiParam()
@ApiProperty()
@ApiPropertyOptional()
@ApiQuery()
@ApiResponse()
@ApiSecurity()
@ApiBasicAuth()
@ApiOAuth2()
@ApiBearerAuth()
@ApiCookieAuth()
@ApiTags()
```
6 changes: 4 additions & 2 deletions docs/openapi-metadata/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ This library is made to be used through an integration with your favorite framew

## Express

```ts
```ts twoslash
// @noErrors
import express from "express";
import { generateDocument } from "openapi-metadata";
import { generateScalarUI } from "openapi-metadata/ui";
Expand All @@ -29,7 +30,8 @@ app.get("/api/docs", (req, res) => {

## Fastify

```ts
```ts twoslash
// @noErrors
import fastify from "fastify";
import { generateDocument } from "openapi-metadata";
import { generateScalarUI } from "openapi-metadata/ui";
Expand Down
44 changes: 23 additions & 21 deletions docs/openapi-metadata/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ title: "Getting started"

::: code-group

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

class UsersController {
@ApiOperation({
method: "get",
pattern: "/users",
methods: ["get"],
path: "/users",
summary: "List users"
})
@ApiResponse({ type: [User] })
Expand All @@ -25,7 +26,7 @@ class UsersController {
}
```

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

class User {
Expand All @@ -40,7 +41,8 @@ class User {
}
```

```ts [index.ts]
```ts [index.ts] twoslash
// @noErrors
import "reflect-metadata";
import { generateDocument } from "openapi-metadata";
import UsersController from "./users_controller";
Expand All @@ -49,7 +51,7 @@ const document = await generateDocument({
controllers: [UsersController],
document: {
info: {
name: "My Api",
title: "My Api",
version: "1.0.0",
},
},
Expand Down Expand Up @@ -109,21 +111,21 @@ To get started, you can use the `generateDocument` function to create an (almost

::: code-group

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

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

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

:::
Expand All @@ -135,14 +137,15 @@ In the following example we have a `UsersController` which declares an operation

::: code-group

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

export default class UsersController {
@ApiOperation({
method: "get",
pattern: "/users",
methods: ["get"],
path: "/users",
summary: "List users",
})
@ApiResponse({ type: [User] })
Expand All @@ -164,7 +167,7 @@ By using the `@ApiProperty` decorator on class we can define the properties of o
::: code-group

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

export default class User {
Expand All @@ -184,18 +187,19 @@ export default class User {

:::

### Add the controller to the generated document
### Register your controller

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

::: code-group

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

const builder = await generateDocument({
const document = await generateDocument({
controllers: [UsersController],
document: {
info: {
Expand All @@ -205,9 +209,7 @@ const builder = await generateDocument({
},
});

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

:::

### Going further
6 changes: 3 additions & 3 deletions docs/openapi-metadata/ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,23 @@ title: UI integrations

## [Scalar](https://scalar.com)

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

generateScalarUI("http://localhost:3000/api");
```

## [Swagger UI](https://swagger.io/tools/swagger-ui/)

```ts
```ts twoslash
import { generateSwaggerUI } from "openapi-metadata/ui";

generateSwaggerUI("http://localhost:3000/api");
```

## [Rapidoc](https://rapidocweb.com/)

```ts
```ts twoslash
import { generateRapidocUI } from "openapi-metadata/ui";

generateRapidocUI("http://localhost:3000/api");
Expand Down
4 changes: 3 additions & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"update-contributors": "node scripts/update-contributors.js"
},
"devDependencies": {
"vitepress": "1.5.0"
"vitepress": "1.5.0",
"@shikijs/vitepress-twoslash": "^1.22.2",
"openapi-metadata": "workspace:*"
}
}
6 changes: 6 additions & 0 deletions packages/openapi-metadata/src/decorators/api-body.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ import { type OperationBodyMetadata, OperationBodyMetadataStorage } from "../met

export type ApiBodyOptions = SetOptional<OperationBodyMetadata, "mediaType">;

/**
* Configures the request body.
* Can be applied to Controllers and Operations.
*
* @see https://swagger.io/specification/#request-body-object
*/
export function ApiBody(options: ApiBodyOptions): MethodDecorator {
return (target, propertyKey) => {
OperationBodyMetadataStorage.defineMetadata(
Expand Down
6 changes: 6 additions & 0 deletions packages/openapi-metadata/src/decorators/api-cookie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import { type OperationParameterMetadata, OperationParameterMetadataStorage } fr

export type ApiCookieOptions = Omit<OperationParameterMetadata, "in">;

/**
* Configures a cookie parameter.
* Can be applied to Operations and Controllers.
*
* @see https://swagger.io/specification/#parameter-object
*/
export function ApiCookie(options: ApiCookieOptions) {
return (target: Object, propertyKey?: string | symbol) => {
OperationParameterMetadataStorage.mergeMetadata(target, [{ in: "cookie", ...options }], propertyKey);
Expand Down
8 changes: 8 additions & 0 deletions packages/openapi-metadata/src/decorators/api-exclude.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import { ExcludeMetadataStorage } from "../metadata/exclude.js";

/**
* Exclude this Controller from the generated schema.
* Useful when working with framework integrations that autoload controllers.
*/
export function ApiExcludeController(): ClassDecorator {
return (target) => {
ExcludeMetadataStorage.defineMetadata(target, true);
};
}

/**
* Exclude this Operation from the generated schema.
* Useful when working with framework integrations that autoload controllers.
*/
export function ApiExcludeOperation(): MethodDecorator {
return (target, propertyKey) => {
ExcludeMetadataStorage.defineMetadata(target, true, propertyKey);
Expand Down
4 changes: 4 additions & 0 deletions packages/openapi-metadata/src/decorators/api-extra-models.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { ExtraModelsMetadataStorage } from "../metadata/extra-models.js";
import type { Thunk, TypeValue } from "../types.js";

/**
* Adds extra models to the generated schema that are not used anywhere else.
* Useful when you want to share models that are not used by your operations.
*/
export function ApiExtraModels(...models: (TypeValue | Thunk<TypeValue>)[]) {
return (target: Object) => {
ExtraModelsMetadataStorage.mergeMetadata(target, models);
Expand Down
Loading

0 comments on commit ca68475

Please sign in to comment.