3.68.0 • Published 4 months ago

adonis-autoswagger v3.68.0

Weekly downloads
-
License
MIT
Repository
github
Last release
4 months ago

Version GitHub stars GitHub watchers GitHub forks

Auto-Generate swagger docs for AdonisJS

💻️ Install

pnpm i adonis-autoswagger #using pnpm

⭐️ Features

  • Creates paths automatically based on routes.ts
  • Creates schemas automatically based on app/Models/*
  • Creates schemas automatically based on app/Interfaces/*
  • Creates schemas automatically based on app/Validators/* (only for adonisJS v6)
  • Rich configuration via comments
  • Works also in production mode
  • node ace docs:generate command

✌️Usage

Create a file /config/swagger.ts

// for AdonisJS v6
import path from "node:path";
import url from "node:url";
// ---

export default {
  // path: __dirname + "/../", for AdonisJS v5
  path: path.dirname(url.fileURLToPath(import.meta.url)) + "/../", // for AdonisJS v6
  title: "Foo", // use info instead
  version: "1.0.0", // use info instead
  description: "", // use info instead
  tagIndex: 2,
  productionEnv: "production", // optional
  info: {
    title: "title",
    version: "1.0.0",
    description: "",
  },
  snakeCase: true,

  debug: false, // set to true, to get some useful debug output
  ignore: ["/swagger", "/docs"],
  preferredPutPatch: "PUT", // if PUT/PATCH are provided for the same route, prefer PUT
  common: {
    parameters: {}, // OpenAPI conform parameters that are commonly used
    headers: {}, // OpenAPI conform headers that are commonly used
  },
  securitySchemes: {}, // optional
  authMiddlewares: ["auth", "auth:api"], // optional
  defaultSecurityScheme: "BearerAuth", // optional
  persistAuthorization: true, // persist authorization between reloads on the swagger page
  showFullPath: false, // the path displayed after endpoint summary
};

In your routes.ts

6️⃣ for AdonisJS v6

import AutoSwagger from "adonis-autoswagger";
import swagger from "#config/swagger";
// returns swagger in YAML
router.get("/swagger", async () => {
  return AutoSwagger.default.docs(router.toJSON(), swagger);
});

// Renders Swagger-UI and passes YAML-output of /swagger
router.get("/docs", async () => {
  return AutoSwagger.default.ui("/swagger", swagger);
  // return AutoSwagger.default.scalar("/swagger"); to use Scalar instead. If you want, you can pass proxy url as second argument here.
  // return AutoSwagger.default.rapidoc("/swagger", "view"); to use RapiDoc instead (pass "view" default, or "read" to change the render-style)
});

5️⃣ for AdonisJS v5

import AutoSwagger from "adonis-autoswagger";
import swagger from "Config/swagger";
// returns swagger in YAML
Route.get("/swagger", async () => {
  return AutoSwagger.docs(Route.toJSON(), swagger);
});

// Renders Swagger-UI and passes YAML-output of /swagger
Route.get("/docs", async () => {
  return AutoSwagger.ui("/swagger", swagger);
});

👍️ Done

Visit http://localhost:3333/docs to see AutoSwagger in action.

Functions

  • async docs(routes, conf): get the specification in YAML format
  • async json(routes, conf): get the specification in JSON format
  • ui(path, conf): get default swagger UI
  • rapidoc(path, style): get rapidoc UI
  • scalar(path): get scalar UI
  • jsonToYaml(json): can be used to convert json() back to yaml

💡 Compatibility

For controllers to get detected properly, please load them lazily.

✅ const TestController = () => import('#controllers/test_controller')
❌ import TestController from '#controllers/test_controller'

🧑‍💻 Advanced usage

Additional configuration

info See Swagger API General Info for details.

securitySchemes

Add/Overwrite security schemes Swagger Authentication for details.

// example to override ApiKeyAuth
securitySchemes: {
  ApiKeyAuth: {
    type: "apiKey"
    in: "header",
    name: "X-API-Key"
  }
}

defaultSecurityScheme

Override the default security scheme.

  • BearerAuth
  • BasicAuth
  • ApiKeyAuth
  • your own defined under securitySchemes

authMiddlewares

If a route uses a middleware named auth, auth:api, AutoSwagger will detect it as a Swagger security method. However, you can implement other middlewares that handle authentication.

Modify generated output

Route.get("/myswagger", async () => {
  const json = await AutoSwagger.json(Route.toJSON(), swagger);
  // modify json to your hearts content
  return AutoSwagger.jsonToYaml(json);
});

Route.get("/docs", async () => {
  return AutoSwagger.ui("/myswagger", swagger);
});

Custom Paths in adonisJS v6

AutoSwagger supports the paths set in package.json. Interfaces are expected to be in app/interfaces. However, you can override this, by modifying package.json as follows.

//...
"imports": {
  // ...
  "#interfaces/*": "./app/custom/path/interfaces/*.js"
  // ...
}
//...

📃 Configure

tagIndex

Tags endpoints automatically

  • If your routes are /api/v1/products/... then your tagIndex should be 3
  • If your routes are /v1/products/... then your tagIndex should be 2
  • If your routes are /products/... then your tagIndex should be 1

ignore

Ignores specified paths. When used with a wildcard (*), AutoSwagger will ignore everything matching before/after the wildcard. /test/_will ignore everything starting with/test/, whereas \*/testwill ignore everything ending with/test.

common

Sometimes you want to use specific parameters or headers on multiple responses.

Example: Some resources use the same filter parameters or return the same headers.

Here's where you can set these and use them with @paramUse() and @responseHeader() @use(). See practical example for further details.


💫 Extend Controllers

Add additional documentation to your Controller-files

@summary (only one) A summary of what the action does

@tag (only one) Set a custom tag for this action

@description (only one) A detailed description of what the action does.

@operationId (only one) An optional unique string used to identify an operation. If provided, these IDs must be unique among all operations described in your API..

@responseBody (multiple)

Format: <status> - <return> - <description>

<return> can be either a <Schema>, <Schema[]>/ or a custom JSON {}

@responseHeader (multiple)

Format: <status> - <name> - <description> - <meta>

@paramType (multiple)

Type can be one of Parameter Types (first letter in uppercase)

@requestBody (only one) A definition of the expected requestBody

Format: <body>

<body> can be either a <Schema>, <Schema[]>/, or a custom JSON {}

@requestFormDataBody (only one) A definition of the expected requestBody that will be sent with formData format.

Schema A model or a validator. Format: <Schema>

Custom format

Format: {"fieldname": {"type":"string", "format": "email"}} This format should be a valid openapi 3.x json.


🤘Examples

@responseBody examples

@responseBody <status> - Lorem ipsum Dolor sit amet

@responseBody <status> // returns standard <status> message

@responseBody <status> - <Model> // returns model specification

@responseBody <status> - <Model[]> // returns model-array specification

@responseBody <status> - <Model>.with(relations, property1, property2.relations, property3.subproperty.relations) // returns a model and a defined relation

@responseBody <status> - <Model[]>.with(relations).exclude(property1, property2, property3.subproperty) // returns model specification

@responseBody <status> - <Model[]>.append("some":"valid json") // append additional properties to a Model

@responseBody <status> - <Model[]>.paginated() // helper function to return adonisJS conform structure like {"data": [], "meta": {}}

@responseBody <status> - <Model[]>.paginated(dataName, metaName) // returns a paginated model with custom keys for the data array and meta object, use `.paginated(dataName)` or `.paginated(,metaName)` if you want to override only one. Don't forget the ',' for the second parameter.

@responseBody <status> - <Model>.only(property1, property2) // pick only specific properties

@requestBody <status> <myCustomValidator> // returns a validator object

@responseBody <status> - {"foo": "bar", "baz": "<Model>"} //returns custom json object and also parses the model
@responseBody <status> - ["foo", "bar"] //returns custom json array

@paramPath and @paramQuery examples

// basicaly same as @response, just without a status
@paramPath <paramName> - Description - (meta)
@paramQuery <paramName> - Description - (meta)

@paramPath id - The ID of the source - @type(number) @required
@paramPath slug - The ID of the source - @type(string)

@paramQuery q - Search term - @type(string) @required
@paramQuery page - the Page number - @type(number)

@requestBody examples

// basicaly same as @response, just without a status
@requestBody <Model> // Expects model specification
@requestBody <myCustomValidator> // Expects validator specification
@requestBody <Model>.with(relations) // Expects model and its relations
@requestBody <Model[]>.append("some":"valid json") // append additional properties to a Model
@requestBody {"foo": "bar"} // Expects a specific JSON

@requestFormDataBody examples

// Providing a raw JSON
@requestFormDataBody {"name":{"type":"string"},"picture":{"type":"string","format":"binary"}} // Expects a valid OpenAPI 3.x JSON
// Providing a Model, and adding additional fields
@requestFormDataBody <Model> // Expects a valid OpenAPI 3.x JSON
@requestFormDataBody <Model>.exclude(property1).append("picture":{"type":"string","format":"binary"}) // Expects a valid OpenAPI 3.x JSON

Practical example

config/swagger.ts

export default {
  path: __dirname + "../",
  title: "YourProject",
  version: "1.0.0",
  tagIndex: 2,
  ignore: ["/swagger", "/docs", "/v1", "/", "/something/*", "*/something"],
  common: {
    parameters: {
      sortable: [
        {
          in: "query",
          name: "sortBy",
          schema: { type: "string", example: "foo" },
        },
        {
          in: "query",
          name: "sortType",
          schema: { type: "string", example: "ASC" },
        },
      ],
    },
    headers: {
      paginated: {
        "X-Total-Pages": {
          description: "Total amount of pages",
          schema: { type: "integer", example: 5 },
        },
        "X-Total": {
          description: "Total amount of results",
          schema: { type: "integer", example: 100 },
        },
        "X-Per-Page": {
          description: "Results per page",
          schema: { type: "integer", example: 20 },
        },
      },
    },
  },
};

app/Controllers/Http/SomeController.ts

export default class SomeController {
  /**
   * @index
   * @operationId getProducts
   * @description Returns array of producs and it's relations
   * @responseBody 200 - <Product[]>.with(relations)
   * @paramUse(sortable, filterable)
   * @responseHeader 200 - @use(paginated)
   * @responseHeader 200 - X-pages - A description of the header - @example(test)
   */
  public async index({ request, response }: HttpContextContract) {}

  /**
   * @show
   * @paramPath id - Describe the path param - @type(string) @required
   * @paramQuery foo - Describe the query param - @type(string) @required
   * @description Returns a product with it's relation on user and user relations
   * @responseBody 200 - <Product>.with(user, user.relations)
   * @responseBody 404
   */
  public async show({ request, response }: HttpContextContract) {}

  /**
   * @update
   * @responseBody 200
   * @responseBody 404 - Product could not be found
   * @requestBody <Product>
   */
  public async update({ request, response }: HttpContextContract) {}

  /**
   * @myCustomFunction
   * @summary Lorem ipsum dolor sit amet
   * @paramPath provider - The login provider to be used - @enum(google, facebook, apple)
   * @responseBody 200 - {"token": "xxxxxxx"}
   * @requestBody {"code": "xxxxxx"}
   */
  public async myCustomFunction({ request, response }: HttpContextContract) {}
}

What does it do?

AutoSwagger tries to extracat as much information as possible to generate swagger-docs for you.

Paths

Automatically generates swagger path-descriptions, based on your application routes. It also detects endpoints, protected by the auth-middlware.

paths

Responses and RequestBody

Generates responses and requestBody based on your simple Controller-Annotation (see Examples)


Schemas

Models

Automatically generates swagger schema-descriptions based on your models

alt

Interfaces

Instead of using param: any you can now use custom interfaces param: UserDetails. The interfaces files need to be located at app/Interfaces/

Extend Models

Add additional documentation to your Models properties.

SoftDelete

Either use compose(BaseModel, SoftDeletes) or add a line @swagger-softdeletes to your Model.

Attention

The below comments MUST be placed 1 line above the property.


@no-swagger Although, autoswagger detects serializeAs: null fields automatically, and does not show them. You can use @no-swagger for other fields.

@enum(foo, bar) If a field has defined values, you can add them into an enum. This is usesfull for something like a status field.

@format(string) Specify a format for that field, i.e. uuid, email, binary, etc...

@example(foo bar) Use this field to provide own example values for specific fields

@props({"minLength": 10, "foo": "bar"}) Use this field to provide additional properties to a field, like minLength, maxLength, etc. Needs to bee valid JSON.

@required Specify that the field is required

// SomeModel.js
@hasMany(() => ProductView)
// @no-swagger
public views: HasMany<typeof ProductView>


@column()
// @enum(pending, active, deleted)
public status: string

@column()
// @example(johndoe@example.com)
public email: string

@column()
// @props({"minLength": 10})
public age: number

Production environment

!WARNING Make sure NODE_ENV=production in your production environment or whatever you set in options.productionEnv

To make it work in production environments, additional steps are required

node ace docs:generate
node ace build --production
cp swagger.yml build/
3.67.0

4 months ago

3.68.0

4 months ago

3.66.0

5 months ago

3.65.0

5 months ago

3.64.0

8 months ago

3.63.0

11 months ago

3.61.0

11 months ago

3.60.0

11 months ago

3.59.0

12 months ago

3.54.0

1 year ago

3.50.0

1 year ago

3.47.0

1 year ago

3.55.0

1 year ago

3.51.0

1 year ago

3.48.0

1 year ago

3.56.0

1 year ago

3.52.0

1 year ago

3.49.0

1 year ago

3.58.0

12 months ago

3.57.0

1 year ago

3.45.0

1 year ago

3.46.0

1 year ago

3.43.0

1 year ago

3.31.0

1 year ago

3.32.0

1 year ago

3.41.0

1 year ago

3.33.0

1 year ago

3.42.0

1 year ago

3.34.0

1 year ago

3.27.0

1 year ago

3.26.0

1 year ago

3.24.0

1 year ago

3.25.0

1 year ago

3.23.0

1 year ago

3.20.0

1 year ago

3.17.0

1 year ago

3.21.0

1 year ago

3.18.0

1 year ago

3.22.0

1 year ago

3.19.0

1 year ago

3.14.0

1 year ago

3.15.0

1 year ago

3.16.0

1 year ago

3.12.0

1 year ago

3.13.0

1 year ago

3.10.0

1 year ago

3.11.0

1 year ago

3.9.0

1 year ago

3.8.0

1 year ago

3.7.0

1 year ago

3.6.0

1 year ago

3.5.0

1 year ago

3.4.0

1 year ago

3.4.1

1 year ago

3.3.1

1 year ago

3.3.0

1 year ago

3.2.1

1 year ago

3.2.0

1 year ago

3.1.1

1 year ago

3.1.0

1 year ago

3.0.1

1 year ago

3.0.0

1 year ago

2.15.1

1 year ago

2.16.1

1 year ago

2.16.0

1 year ago

2.13.1

1 year ago

2.14.1

1 year ago

2.14.0

1 year ago

2.13.0

1 year ago

2.11.0

1 year ago

2.11.1

1 year ago

2.12.1

1 year ago

2.10.1

1 year ago

2.10.0

1 year ago

2.9.1

1 year ago

2.9.0

1 year ago

2.8.1

1 year ago

2.8.0

1 year ago

2.7.0

1 year ago

2.7.1

1 year ago

2.6.0

1 year ago

2.2.1

1 year ago

2.2.0

1 year ago

2.0.2

1 year ago

2.4.1

1 year ago

2.4.0

1 year ago

2.0.1

1 year ago

2.0.0

1 year ago

2.3.0

1 year ago

2.5.0

1 year ago

2.3.1

1 year ago

2.5.1

1 year ago

1.9.1

2 years ago

1.10.1

2 years ago

1.8.2

2 years ago

1.8.5

2 years ago

1.8.3

2 years ago

1.8.1

3 years ago

1.8.0

3 years ago

1.7.8

3 years ago

1.7.6

3 years ago

1.2.0

4 years ago

1.6.4

3 years ago

1.6.3

3 years ago

1.6.2

3 years ago

1.6.1

3 years ago

1.6.0

3 years ago

1.4.0

3 years ago

1.6.11

3 years ago

1.6.10

3 years ago

1.7.5

3 years ago

1.7.4

3 years ago

1.6.12

3 years ago

1.7.3

3 years ago

1.7.2

3 years ago

1.7.1

3 years ago

1.7.0

3 years ago

1.5.1

3 years ago

1.5.0

3 years ago

1.3.1

3 years ago

1.3.0

3 years ago

1.1.12

4 years ago

1.1.14

4 years ago

1.1.13

4 years ago

1.6.9

3 years ago

1.6.8

3 years ago

1.6.7

3 years ago

1.6.6

3 years ago

1.6.5

3 years ago

1.1.11

4 years ago

1.1.10

4 years ago

1.1.9

4 years ago

1.1.7

4 years ago

1.1.6

4 years ago

1.1.5

4 years ago

1.1.4

4 years ago

1.1.3

4 years ago

1.1.2

4 years ago

1.1.1

4 years ago

1.1.0

4 years ago

1.0.12

4 years ago

1.0.11

4 years ago

1.0.10

4 years ago

1.0.9

4 years ago

1.0.8

4 years ago

1.0.7

4 years ago

1.0.6

4 years ago

1.0.5

4 years ago

1.0.4

4 years ago

1.0.3

4 years ago

1.0.2

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago