inversify-express-typebox-openapi
TypeScript icon, indicating that this package has built-in type declarations

0.1.0 • Public • Published

Inversify Express Typebox OpenAPI

Generate OpenAPI specification during runtime from inversify-express-utils controllers and @sinclair/typebox schemas.

Features

Usage

Installation

npm install inversify-express-typebox-openapi

Example

export enum UserState {
  Active = 'active',
  Inactive = 'inactive',
  Pending = 'pending',
}

export const userStateSchema = Type.Enum(UserState, { $id: 'UserState' });

export const userSchema = Type.Object(
  {
    id: Type.Number(),
    name: Type.String(),
    email: Type.String({}),
    createdAt: Type.String({ format: 'date-time' }),
    state: userStateSchema,
  },
  { $id: 'User' },
);

export type User = Static<typeof userSchema>;

@Controller('/users')
@Tags('User')
@Security({ bearerAuth: ['read:user'] })
export class UserController {
  @Get('me')
  @Response(200, {
    description: 'The user from the session',
    content: { schema: userSchema },
  })
  @Response(401, { description: 'Unauthorized' })
  @Security({ bearerAuth: ['read:session'] })
  public getUserFromSession(
    @injectResponse() res: ExpressResponse,
    @Cookie('sessionId', Type.String()) sessionId: string,
  ): void {
    // ...
  }

  @Get('/')
  @Response(200, {
    description: 'List of all users',
    content: { schema: Type.Array(userSchema) },
  })
  @OperationId('getAllUsers')
  public get(
    @Query('state', Type.Optional(userStateSchema))
    userState?: UserState,
    @Header('Accept-Language', Type.Optional(Type.String()), {
      description: 'Falls back to english if not provided',
    })
    _acceptLanguage?: string,
  ): User[] {
    // ...
  }

  @Deprecated()
  @Get('/active')
  @Response(200, {
    description: 'List of all active users',
    content: { schema: Type.Array(userSchema) },
  })
  public getAllActiveUsers(): User[] {
    // ...
  }

  @Get('/:userId')
  @Response(200, {
    description: 'The requested user',
    content: { schema: userSchema },
  })
  @Response(404, { description: 'User not found' })
  public getUserById(
    @Path('userId', Type.Number()) userId: number,
    @injectResponse() res: ExpressResponse,
    @Header('Accept-Language', Type.Optional(Type.String()))
    _acceptLanguage?: string,
  ): void {
    // ...
  }

  @Post('/')
  @Response(201, {
    description: 'The created user',
    content: { schema: userSchema },
  })
  @Security({ bearerAuth: ['write:user'] })
  public createUser(
    @Body(userSchema) user: User,
    @injectResponse() res: ExpressResponse,
  ): void {
    // ...
  }

  @Put('/:userId')
  @Response(200, { description: 'The updated user' })
  @Response(404, { description: 'User not found' })
  @Security({ bearerAuth: ['write:user'] })
  public updateUser(
    @Path('userId', Type.Number()) userId: number,
    @Body(userSchema) user: User,
    @injectResponse() res: ExpressResponse,
  ): void {
    // ...
  }

  @Patch('/:userId/state')
  @Response(200, {
    description: 'The updated user',
    content: { schema: userSchema },
  })
  @Response(404, { description: 'User not found' })
  @Security({ bearerAuth: ['write:user'] })
  public patchUserState(
    @Path('userId', Type.Number()) userId: number,
    @Body(userStateSchema) userState: UserState,
    @injectResponse() res: ExpressResponse,
  ): void {
    // ...
  }

  @Delete('/:userId')
  @Response(204, { description: 'User deleted' })
  @Response(404, { description: 'User not found' })
  @Security({ bearerAuth: ['delete:user'] })
  public deleteUser(
    @Path('userId', Type.Number()) userId: number,
    @injectResponse() res: ExpressResponse,
  ): void {
    // ...
  }
}

References

Create identifiable objects

This package supports references. It will add any object that has an $id property to the components map of the OpenApi specification. There is a helper function for defining identifiable/referenceable objects called identifiable. The value of $id will be used as the key within the components map.

import { identifiable } from 'inversify-express-typebox-openapi';
import { type ExampleObject } from 'openapi3-ts/oas31';

const postExample = identifiable<ExampleObject>(
  {
    value: {
      id: 1,
      content: 'This is a post',
    },
  },
  { $id: 'PostExample' },
);

Create identifiable Typebox schemas

Typebox schemas support this out of the box:

import { Type } from '@sinclair/typebox';

export const postSchema = Type.Object(
  {
    id: Type.Number(),
    content: Type.String(),
  },
  { $id: 'PostSchema' },
);

withoutId helper

In case the create identifiable objects need to be reused without their $id property, the helper function withoutId can be used.

import { withoutId } from 'inversify-express-typebox-openapi';

const example = withoutId({
  $id: 'example'
  id: 1,
});

// example = { id: 1 }

Decorators

injectRequest

Is an alias for inversify-express-utils request decorator. May be extended with functionality at a later stage of development.

injectResponse

Is an alias for inversify-express-utils response decorator. May be extended with functionality at a later stage of development.

injectNext

Is an alias for inversify-express-utils next decorator. May be extended with functionality at a later stage of development.

AllowEmtpyValue

Controller Method Parameter

Sets the ability to pass empty-valued parameters. This is valid only for query parameters and allows sending a parameter with an empty value.

class ExampleController {
  public getUsers(
    @AllowEmptyValue() @Query('status', Type.String()) status: string,
  ) {
    // ....
  }
}

This can also be achieved through the Query decorator:

class ExampleController {
  public getUsers(
    @Query('status', Type.String(), { allowEmptyValue: true }) status: string,
  ) {
    // ....
  }
}

AllowReserved

Controller Method Parameter

Specify whether the parameter value SHOULD allow reserved characters, as defined by [RFC3986] :/?#[]@!$&'()*+,;= to be included without percent-encoding.

class ExampleController {
  public getUsers(
    @AllowReserved() @Query('q', Type.String()) searchQuery: string,
  ) {
    // ....
  }
}

This can also be achieved through the Query decorator:

class ExampleController {
  public getUsers(
    @Query('q', Type.String(), { allowReserved: true }) searchQuery: string,
  ) {
    // ....
  }
}

Body

Controller Method Parameter

Specify a body parameter.

const userSchema = Type.Object({
  id: Type.Number(),
  name: Type.String(),
});
type User = Static<typeof userSchema>;

// ...
class ExampleController {
  // ...
  public createUser(@Body(userSchema) userDto: User) {
    // ....
  }
}

Cookie

Controller Method Parameter

Specify a cookie parameter.

// ...
class ExampleController {
  // ...
  public get(@Cookie('Cookie', Type.String()) cookie: string) {
    // ....
  }
}

Delete

Controller Method Parameter

Specify a delete method.

// ...
class ExampleController {
  @Delete('/users/{userId}')
  public deleteUser(/* ... */) {
    // ....
  }
}

Deprecated

Controller Method Parameter

Flag a parameter, a method or all methods of a controller as deprecated. Deprecated parameters will have required set to false.

// ...
@Deprecated()
class ExampleController {
  // ...
}

// ...
class ExampleController {
  // ...
  @Deprecated()
  public getUser() {
    // ...
  }
}

// ...
class ExampleController {
  // ...
  public getUser(@Deprecated() @Path('userId', Type.String())) {

  }
}

Description

Controller Method Parameter

Specify a description for methods and parameters.

class ExampleController {
  @Description('Get all users')
  public getUsers() {
    // ....
  }
}

When used on a controller, it is applied to each of its methods.

Parameter descriptions can also be achieved through any of the parameter decorators:

class ExampleController {
  public getUsers(
    @Query('q', Type.String(), { description: 'Search query' })
    searchQuery: string,
  ) {
    // ....
  }
}

Example

Controller Method Parameter

Specify an example for a parameter value.

class ExampleController {
  public getUsers(
    @Example('Search query') @Query('q', Type.String()) searchQuery: string,
  ) {
    // ....
  }
}

This can also be achieved through any of the parameter decorators:

class ExampleController {
  public getUsers(
    @Query('q', Type.String(), { example: 'Search query' }) searchQuery: string,
  ) {
    // ....
  }
}

Examples

Controller Method Parameter

Specify a map of examples for a parameter value:

class ExampleController {
  public createUser(
    @Examples({
      admin: {
        value: { name: 'admin', role: 'admin' },
      },
      guest: {
        value: { name: 'guest', role: null },
      },
    })
    @Body(userSchema)
    userDto: User,
  ) {
    // ....
  }
}

This can also be achieved through any of the parameter decorators:

class ExampleController {
  public createUser(
    @Body(userSchema, {
      examples: {
        admin: {
          value: { name: 'admin', role: 'admin' },
        },
        guest: {
          value: { name: 'guest', role: null },
        },
      },
    })
    userDto: User,
  ) {
    // ....
  }
}

Explode

Controller Method Parameter

Specify that property values of the type array or object generate separate parameters for each value of the array, or key-value-pair of the map.

// ...
class ExampleController {
  // ...
  public getUsers(
    @Explode() @Query('id', Type.Array(Type.String()) ids: string[],
  ) {
    // ....
  }
}

This can also be achieved through any of the parameter decorators:

// ...
class ExampleController {
  // ...
  public getUsers(
    @Query('id', Type.Array(Type.String(), { explode: true }) ids: string[],
  ) {
    // ....
  }
}

ExternalDocs

Controller Method Parameter

Specify external documentation.

// ...
@ExternalDocs({
  description: 'Official documentation',
  url: 'https://example.org',
})
class ExampleController {
  // ...
  public getUsers() {
    // ....
  }
}

// ...
class ExampleController {
  // ...
  @ExternalDocs({
    description: 'Official documentation',
    url: 'https://example.org',
  })
  public getUsers() {
    // ....
  }
}

// ...
class ExampleController {
  // ...
  public getUser(
    @ExternalDocs({
      description: 'Official documentation',
      url: 'https://example.org',
    })
    @Path('id', Type.String()))
    id: string
  {
    // ....
  }
}

Get

Controller Method Parameter

Specify a get method.

// ...
class ExampleController {
  @Get('/users')
  public getUsers() {
    // ....
  }
}

Head

Controller Method Parameter

Specify a head method.

// ...
class ExampleController {
  @Head('/file/xyz.zip')
  public download() {
    // ....
  }
}

Header

Controller Method Parameter

Specify a header parameter.

// ...
class ExampleController {
  // ...
  public get(@Header('Authorization', Type.String()) authToken: string) {
    // ....
  }
}

OperationId

Controller Method Parameter

Specify a custom operation id for a method. By default, the operation id is the method name.

class ExampleController {
  @OperationId('customOperationId')
  @Get('/users')
  public getUsers() {
    // ....
  }
}

This example will result in the operation id ExampleController_customOperationId.

When used on a controller, the prefix (by default the controller name) is replaced with the custom operation id. The following example will result in the operation id customControllerName_customOperationId:

@OperationId('customControllerName')
class ExampleController {
  @OperationId('customOperationId')
  @Get('/users')
  public getUsers() {
    // ....
  }
}

Patch

Controller Method Parameter

Specify a patch method.

// ...
class ExampleController {
  @Patch('/users/{userId}')
  public updateUser() {
    // ....
  }
}

Path

Controller Method Parameter

Specify a path parameter.

// ...
class ExampleController {
  @Get('/users/{userId}')
  public getUser(@Path('userId', Type.String()) userId: string) {
    // ...
  }
}

Post

Controller Method Parameter

Specify a post method.

// ...
class ExampleController {
  @Post('/users')
  public createUser() {
    // ....
  }
}

Put

Controller Method Parameter

Specify a put method.

// ...
class ExampleController {
  @Put('/users/{userId}')
  public replaceUser() {
    // ....
  }
}

Query

Controller Method Parameter

Specify a query parameter.

// ...
class ExampleController {
  // ...
  public getUsers(@Query('query', Type.String()) query: string) {
    // ...
  }
}

Response

Controller Method Parameter

Specify a possible response for a method.

class ExampleController {
  // ...
  @Response(200, {
    description: 'IDs of users',
    content: { schema: Type.Array(Type.Number()) },
  })
  public getUserIds() {
    // ...
  }
}

Use default instead of an HTTP status code for a default error response.

Security

Controller Method Parameter

Specify the security requirements for a method.

// ...
@Security({ securityScheme: ['scopeA', 'scopeB'] })
class ExampleController {
  // ...
}

When used on a controller, it is applied to each of its methods.

Multiple @Security decorators onto one controller/method extend the requirements.

Style

Controller Method Parameter

Describes how the parameter value will be serialized depending on the type of the parameter value.

// ...
class ExampleController {
  // ...
  public getUser(
    @Style('simple') @Path('userId', Type.String()) status: string,
  ) {
    // ....
  }
}

This can also be achieved through any of the parameter decorators:

// ...
class ExampleController {
  // ...
  public getUser(
    @Path('userId', Type.String(), { style: 'simple' }) status: string,
  ) {
    // ....
  }
}

Summary

Controller Method Parameter

Specify a summary for an operation.

// ...
class ExampleController {
  // ....
  @Summary('Retrieves all the users form the database')
  public getUser() {
    // ....
  }
}

Tags

Controller Method Parameter

Specify tags for a method.

// ...
class ExampleController {
  // ....
  @Tags('V1', 'User')
  public getUser() {
    // ....
  }
}

When used on a controller, it is applied to each of its methods.

Package Sidebar

Install

npm i inversify-express-typebox-openapi

Weekly Downloads

26

Version

0.1.0

License

ISC

Unpacked Size

106 kB

Total Files

33

Last publish

Collaborators

  • sedlatschek