diff --git a/docs/_sidebar.md b/docs/_sidebar.md
index cc6bd20..d219d0d 100644
--- a/docs/_sidebar.md
+++ b/docs/_sidebar.md
@@ -5,3 +5,4 @@
* Migrations
* * [Migrations for Version 1](/migrations/MIGRATIONS_v1.md)
* * [Migrations for Version 2](/migrations/MIGRATIONS_v2.md)
+* * [Migrations for version 3](/migrations/MIGRATIONS_v3.md)
diff --git a/docs/api.md b/docs/api.md
index 0568221..bb1dff6 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -48,6 +48,9 @@ __Options:__
- `getOperationArgs({ service, path, config, apiPath, version })` - Function to generate args that the methods for operations will consume, can also customize default tag and model generation
- `getOperationsRefs(model, service)` - Function to generate refs that the methods for operations will consume, see service.docs.refs option
- `schemasGenerator(service, model, modelName, schemas)` - Function to generate the json schemas for a service
+ - `schemaNames`
+ - `list(model)` - function to return the default name for the list schema, defaults to `${model}List` if not provided
+ - `pagination(model)` - function to return the default name for the list schema, defaults to `${model}Pagination` if not provided
- `operationGenerators` - Generator functions to fully customize specification generation for operations. To disable the generation of a method return false.
- `find`|`get`|`create`|`update`|`patch`|`remove` - Generator function for the specific operation.
- `updateMulti`|`patchMulti`|`removeMulti` - Generator function for the "multi mode" version of the specific operation
@@ -121,10 +124,50 @@ __Options:__
- `find`|`get`|`create`|`update`|`patch`|`remove`|`nameOfCustomMethod` - Custom (parts of the) specification for the operation, can alternatively be set as doc property of the method. To disable the generation set to false.
- `updateMulti`|`patchMulti`|`removeMulti` - if "multi mode" is enabled for the specific method, custom parts of the specification can be overwritten. To disable the generation set to false.
- `all` - Custom (parts of the) specification for all operations.
-- `refs` (*optional*) - Change the refs that are used for different operations: findResponse, getResponse, createRequest, createResponse, updateRequest, updateResponse, patchRequest, patchResponse, removeResponse, {customMethodName[Request|Response]}
+- `refs` (*optional*) - Object with mapping of refs that are used for different operations, by setting the schema name
+ - `findResponse`
+ - `getResponse`
+ - `createRequest`
+ - `createResponse`
+ - `createMultiRequest` - only with `openApiVersion` 3
+ - `createMultiResponse` - only with `openApiVersion` 3
+ - `updateRequest`
+ - `updateResponse`
+ - `updateMultiRequest`
+ - `updateMultiResponse`
+ - `patchRequest`
+ - `patchResponse`
+ - `patchMultiRequest`
+ - `patchMultiResponse`
+ - `removeResponse`
+ - `removeMultiResponse`
+ - `filterParameter`
+ - `sortParameter`
+ - `queryParameters` - only with `openApiVersion` 3
+ - `{customMethodName[Request|Response]}`
+- `schemaNames` (*optional*) - Adjust the automatic generation of schema names
+ - `list(model)` - Function to return the name for the list schema, defaults to `${model}List` if not provided
+ - `pagination(model)` - Function to return the name for the list schema, defaults to `${model}Pagination` if not provided
- `pathParams` (*optional*) - Object with param name as key and the definition as value, should be used when using "global" path parameters
- `overwriteTagSpec` (*optional*, default: `false`) - If tag is already defined in the specs, should be overwritten from this service
+### `swagger.createSwaggerServiceOptions(options)`
+
+Helper function to create a `service.docs` object, based on the provided schemas.
+Only the `schemas`, `refs` and `model` properties will be generated.
+
+__Options:__
+- `schemas` - Object with TypeBox or json schemas
+ - Provide the generated schemas with `xxxSchema`, `xxxDataSchema` and `xxxQuerySchema` naming schema
+ - This will generate the `schemas` and `refs` and `model` based on the provided schemas
+ - Provide any schema that has an `$id` with any name
+ - This will just add the schema that can be consumed in refs or customized operations specifications
+ - Provide any schema that has an `$id` with a ref as key, check `service.docs.refs` for allowed refs
+ - This will add the schema and use it for the given ref
+- `docs` - Any service.docs options that will be merged into the resulting object and would overwrite anything that will be generated
+- `sanitizeSchema` - A function that sanitizes the schema from properties that are not allowed in an OpenApi specification.
+ If not provided a default implementation will be used.
+
### Path support to update nested structures
To be able to set only parts of a nested structure the keys of a specification object (used to define operation specifications) can be the path that should be updated.
@@ -140,7 +183,7 @@ Valid unshift syntax:
- `path[-]`
- `path[-D]` with D being digits (needed to be able to define more than one element to unshift, the digits does not refer to a position)
-### `swaggerUI.customMethod(verb, path)`
+### `swagger.customMethod(verb, path)`
To define the rest method of a custom method it has to be wrapped/annotated with `customMethod`.
For Feathers 5 the custom method has to be added to the methods when registering the service.
diff --git a/docs/examples/_sidebar.md b/docs/examples/_sidebar.md
index 36a1cf4..2f14ee9 100644
--- a/docs/examples/_sidebar.md
+++ b/docs/examples/_sidebar.md
@@ -7,3 +7,5 @@
* * [SwaggerUI](/examples/ui.md)
* * [Prefixed Routes](/examples/prefixed_routes.md)
* * [Custom Methods](/examples/custom_methods.md)
+* * [Using Schemas of Feathersjs v5 (dove)](/examples/generated_service_v5.md)
+* * [Authentication with Feathersjs v5 (dove)](/examples/authentication_v5.md)
diff --git a/docs/examples/authentication_v5.md b/docs/examples/authentication_v5.md
new file mode 100644
index 0000000..2a12167
--- /dev/null
+++ b/docs/examples/authentication_v5.md
@@ -0,0 +1,233 @@
+### Example with feathers generated authentication on feathersjs v5 (dove)
+
+1. When you have generated the app with authentication you have to add some things to the initial
+ specs when registering feathers swagger.
+
+ ```typescript
+ app.configure(
+ swagger({
+ specs: {
+ info: {
+ title: 'Feathers app with swagger with authentication',
+ version: '1.0.0',
+ description: '...',
+ },
+ components: {
+ securitySchemes: {
+ BearerAuth: {
+ type: 'http',
+ scheme: 'bearer',
+ },
+ },
+ },
+ security: [{ BearerAuth: [] }],
+ },
+ // other options ...
+ }),
+ );
+ ```
+
+2. Add documentation to the authentication service (`src/authentication.ts`).
+ This example shows local authentication.
+
+ ```typescript
+ import { AuthenticationService, JWTStrategy } from '@feathersjs/authentication';
+ import { LocalStrategy } from '@feathersjs/authentication-local';
+ import type { Application } from './declarations';
+ import { ServiceSwaggerOptions } from '../../feathers-swagger';
+
+ declare module './declarations' {
+ interface ServiceTypes {
+ authentication: AuthenticationService;
+ }
+ }
+
+ declare module '@feathersjs/authentication' {
+ class AuthenticationService {
+ docs: ServiceSwaggerOptions;
+ }
+ }
+
+ export const authentication = (app: Application) => {
+ const authentication = new AuthenticationService(app);
+
+ authentication.docs = {
+ idNames: {
+ remove: 'accessToken',
+ },
+ idType: 'string',
+ securities: ['remove', 'removeMulti'],
+ multi: ['remove'],
+ schemas: {
+ authRequest: {
+ type: 'object',
+ properties: {
+ strategy: { type: 'string' },
+ email: { type: 'string' },
+ password: { type: 'string' },
+ },
+ },
+ authResult: {
+ type: 'object',
+ properties: {
+ accessToken: { type: 'string' },
+ authentication: {
+ type: 'object',
+ properties: {
+ strategy: { type: 'string' },
+ },
+ },
+ payload: {
+ type: 'object',
+ properties: {}, // TODO
+ },
+ user: { $ref: '#/components/schemas/User' },
+ },
+ },
+ },
+ refs: {
+ createRequest: 'authRequest',
+ createResponse: 'authResult',
+ removeResponse: 'authResult',
+ removeMultiResponse: 'authResult',
+ },
+ operations: {
+ remove: {
+ description: 'Logout the currently logged in user',
+ 'parameters[0].description': 'accessToken of the currently logged in user',
+ },
+ removeMulti: {
+ description: 'Logout the currently logged in user',
+ parameters: [],
+ },
+ },
+ };
+
+ authentication.register('jwt', new JWTStrategy());
+ authentication.register('local', new LocalStrategy());
+
+ app.use('authentication', authentication);
+ };
+ ```
+
+3. Set the `security` option for `service.docs` like shown in
+ [Using Schemas of Feathersjs v5 (dove)](/examples/generated_service_v5.md) for methods that are protected.
+ If all methods are protected `all` can be used.
+
+4. If you want to provide simple authentication usage on the SwaggerUI using Email/Username and Password,
+ you can use the [Swagger UI Plugin ApiKeyAuthForm](https://github.com/Mairu/swagger-ui-apikey-auth-form).
+
+ Here is an example of an `openapi.ts` swagger configuration file, that can used with `api.configure()`;
+
+ ```typescript
+ import swagger, { FnSwaggerUiGetInitializerScript } from 'feathers-swagger';
+ import type { Application } from './declarations';
+
+ const getSwaggerInitializerScript: FnSwaggerUiGetInitializerScript = ({ docsJsonPath, ctx }) => {
+ const headers = ctx && ctx.headers;
+ const basePath = headers!['x-forwarded-prefix'] ?? '';
+
+ // language=JavaScript
+ return `
+ window.onload = function () {
+ var script = document.createElement('script');
+ script.onload = function () {
+ window.ui = SwaggerUIBundle({
+ url: "${basePath}${docsJsonPath}",
+ dom_id: '#swagger-ui',
+ deepLinking: true,
+ presets: [
+ SwaggerUIBundle.presets.apis,
+ SwaggerUIStandalonePreset,
+ SwaggerUIApiKeyAuthFormPlugin,
+ ],
+ plugins: [
+ SwaggerUIBundle.plugins.DownloadUrl
+ ],
+ layout: "StandaloneLayout",
+ configs: {
+ apiKeyAuthFormPlugin: {
+ forms: {
+ BearerAuth: {
+ fields: {
+ email: {
+ type: 'text',
+ label: 'E-Mail-Address',
+ },
+ password: {
+ type: 'password',
+ label: 'Password',
+ },
+ },
+ authCallback(values, callback) {
+ window.ui.fn.fetch({
+ url: '/authentication',
+ method: 'post',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ strategy: 'local',
+ ...values,
+ }),
+ }).then(function (response) {
+ const json = JSON.parse(response.data);
+ if (json.accessToken) {
+ callback(null, json.accessToken);
+ } else {
+ callback('error while login');
+ }
+ }).catch(function (err) {
+ console.log(err, Object.entries(err));
+ callback('error while login');
+ });
+ },
+ }
+ },
+ localStorage: {
+ BearerAuth: {}
+ }
+ }
+ }
+ });
+ };
+
+ script.src = '//cdn.jsdelivr.net/npm/@mairu/swagger-ui-apikey-auth-form@1/dist/swagger-ui-apikey-auth-form.js';
+ document.head.appendChild(script)
+ };
+ `;
+ };
+
+ export default (app: Application) => {
+ // If you don't use custom methods this line can be removed
+ app.configure(swagger.customMethodsHandler);
+
+ app.configure(
+ swagger({
+ specs: {
+ info: {
+ title: 'Example with Authentication',
+ version: '1.0.0',
+ description: 'Example with Authentication and SwaggerUI ApiKeyAuthForm plugin',
+ },
+ components: {
+ securitySchemes: {
+ BearerAuth: {
+ type: 'http',
+ scheme: 'bearer',
+ },
+ },
+ },
+ security: [{ BearerAuth: [] }],
+ },
+ ui: swagger.swaggerUI({ getSwaggerInitializerScript }),
+ }),
+ );
+ };
+ ```
+
+ Here is a preview together with a user service from [Using Schemas of Feathersjs v5 (dove)](/examples/generated_service_v5.md):
+
+
+[filename](../swagger-ui/index.html?url=../examples/authentication_v5_plugin.json ':include class=swui-preview')
diff --git a/docs/examples/authentication_v5_plugin.json b/docs/examples/authentication_v5_plugin.json
new file mode 100644
index 0000000..f3429a3
--- /dev/null
+++ b/docs/examples/authentication_v5_plugin.json
@@ -0,0 +1,708 @@
+{
+ "info": {
+ "title": "Testing feathers swagger with dove",
+ "version": "1.0.0",
+ "description": "Testing feathers swagger with dove using koa"
+ },
+ "components": {
+ "securitySchemes": {
+ "BearerAuth": {
+ "type": "http",
+ "scheme": "bearer"
+ }
+ },
+ "schemas": {
+ "authRequest": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ }
+ }
+ },
+ "authResult": {
+ "type": "object",
+ "properties": {
+ "accessToken": {
+ "type": "string"
+ },
+ "authentication": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string"
+ }
+ }
+ },
+ "payload": {
+ "type": "object",
+ "properties": {}
+ },
+ "user": {
+ "$ref": "#/components/schemas/User"
+ }
+ }
+ },
+ "User": {
+ "type": "object",
+ "properties": {
+ "email": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "id": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "email",
+ "password",
+ "id"
+ ]
+ },
+ "UserData": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "email": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "email",
+ "password"
+ ]
+ },
+ "UserQuery": {
+ "type": "object",
+ "properties": {
+ "$sort": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "email": {
+ "minimum": -1,
+ "maximum": 1,
+ "type": "integer"
+ },
+ "password": {
+ "minimum": -1,
+ "maximum": 1,
+ "type": "integer"
+ },
+ "id": {
+ "minimum": -1,
+ "maximum": 1,
+ "type": "integer"
+ }
+ }
+ },
+ "$select": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "email",
+ "password",
+ "id"
+ ]
+ }
+ },
+ "email": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "$gt": {
+ "type": "string"
+ },
+ "$gte": {
+ "type": "string"
+ },
+ "$lt": {
+ "type": "string"
+ },
+ "$lte": {
+ "type": "string"
+ },
+ "$ne": {
+ "type": "string"
+ },
+ "$in": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "$nin": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "password": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "$gt": {
+ "type": "string"
+ },
+ "$gte": {
+ "type": "string"
+ },
+ "$lt": {
+ "type": "string"
+ },
+ "$lte": {
+ "type": "string"
+ },
+ "$ne": {
+ "type": "string"
+ },
+ "$in": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "$nin": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "id": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "$gt": {
+ "type": "number"
+ },
+ "$gte": {
+ "type": "number"
+ },
+ "$lt": {
+ "type": "number"
+ },
+ "$lte": {
+ "type": "number"
+ },
+ "$ne": {
+ "type": "number"
+ },
+ "$in": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ }
+ },
+ "$nin": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ },
+ "UserPatchData": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "email": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ }
+ }
+ },
+ "UserList": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/User"
+ }
+ },
+ "UserPagination": {
+ "title": "User pagination result",
+ "type": "object",
+ "properties": {
+ "total": {
+ "type": "integer"
+ },
+ "limit": {
+ "type": "integer"
+ },
+ "skip": {
+ "type": "integer"
+ },
+ "data": {
+ "$ref": "#/components/schemas/UserList"
+ }
+ }
+ }
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "paths": {
+ "/authentication": {
+ "post": {
+ "parameters": [],
+ "responses": {
+ "201": {
+ "description": "created",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/authResult"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "not authenticated"
+ },
+ "500": {
+ "description": "general error"
+ }
+ },
+ "description": "Creates a new resource with data.",
+ "summary": "",
+ "tags": [
+ "authentication"
+ ],
+ "security": [],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/authRequest"
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "parameters": [],
+ "responses": {
+ "200": {
+ "description": "success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/authResult"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "not authenticated"
+ },
+ "500": {
+ "description": "general error"
+ }
+ },
+ "description": "Logout the currently logged in user",
+ "summary": "",
+ "tags": [
+ "authentication"
+ ],
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ]
+ }
+ },
+ "/authentication/{accessToken}": {
+ "delete": {
+ "parameters": [
+ {
+ "in": "path",
+ "name": "accessToken",
+ "description": "accessToken of the currently logged in user",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/authResult"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "not authenticated"
+ },
+ "404": {
+ "description": "not found"
+ },
+ "500": {
+ "description": "general error"
+ }
+ },
+ "description": "Logout the currently logged in user",
+ "summary": "",
+ "tags": [
+ "authentication"
+ ],
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ]
+ }
+ },
+ "/users": {
+ "get": {
+ "parameters": [
+ {
+ "description": "Number of results to return",
+ "in": "query",
+ "name": "$limit",
+ "schema": {
+ "type": "integer"
+ }
+ },
+ {
+ "description": "Number of results to skip",
+ "in": "query",
+ "name": "$skip",
+ "schema": {
+ "type": "integer"
+ }
+ },
+ {
+ "description": "Query parameters",
+ "in": "query",
+ "name": "filter",
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "$ref": "#/components/schemas/UserQuery"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UserPagination"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "not authenticated"
+ },
+ "500": {
+ "description": "general error"
+ }
+ },
+ "description": "Retrieves a list of all resources from the service.",
+ "summary": "",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ]
+ },
+ "post": {
+ "parameters": [],
+ "responses": {
+ "201": {
+ "description": "created",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "not authenticated"
+ },
+ "500": {
+ "description": "general error"
+ }
+ },
+ "description": "Creates a new resource with data.",
+ "summary": "",
+ "tags": [
+ "users"
+ ],
+ "security": [],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UserData"
+ }
+ }
+ }
+ }
+ }
+ },
+ "/users/{id}": {
+ "get": {
+ "parameters": [
+ {
+ "in": "path",
+ "name": "id",
+ "description": "ID of User to return",
+ "schema": {
+ "type": "integer"
+ },
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "not authenticated"
+ },
+ "404": {
+ "description": "not found"
+ },
+ "500": {
+ "description": "general error"
+ }
+ },
+ "description": "Retrieves a single resource with the given id from the service.",
+ "summary": "",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ]
+ },
+ "put": {
+ "parameters": [
+ {
+ "in": "path",
+ "name": "id",
+ "description": "ID of User to update",
+ "schema": {
+ "type": "integer"
+ },
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "not authenticated"
+ },
+ "404": {
+ "description": "not found"
+ },
+ "500": {
+ "description": "general error"
+ }
+ },
+ "description": "Updates the resource identified by id using data.",
+ "summary": "",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UserData"
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "parameters": [
+ {
+ "in": "path",
+ "name": "id",
+ "description": "ID of User to update",
+ "schema": {
+ "type": "integer"
+ },
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "not authenticated"
+ },
+ "404": {
+ "description": "not found"
+ },
+ "500": {
+ "description": "general error"
+ }
+ },
+ "description": "Updates the resource identified by id using data.",
+ "summary": "",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UserPatchData"
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "parameters": [
+ {
+ "in": "path",
+ "name": "id",
+ "description": "ID of User to remove",
+ "schema": {
+ "type": "integer"
+ },
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "not authenticated"
+ },
+ "404": {
+ "description": "not found"
+ },
+ "500": {
+ "description": "general error"
+ }
+ },
+ "description": "Removes the resource with id.",
+ "summary": "",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ]
+ }
+ }
+ },
+ "openapi": "3.0.3",
+ "tags": [
+ {
+ "name": "authentication",
+ "description": "A authentication service"
+ },
+ {
+ "name": "users",
+ "description": "A users service"
+ }
+ ]
+}
diff --git a/docs/examples/generated_service_v5.md b/docs/examples/generated_service_v5.md
new file mode 100644
index 0000000..dbe85de
--- /dev/null
+++ b/docs/examples/generated_service_v5.md
@@ -0,0 +1,39 @@
+### Example with feathers generated service based on feathersjs v5 (dove)
+
+1. Go into your `src/services/{$name}` folder, and open the service you want to edit `${name}.[tj]s`
+2. Import the helper function and import the schemas (example for user service):
+```js
+ import { createSwaggerServiceOptions } from 'feathers-swagger';
+ import {
+ userDataValidator,
+ userQueryValidator,
+ userResolver,
+ userDataResolver,
+ userQueryResolver,
+ userExternalResolver,
+ // the lines below are added
+ userDataSchema,
+ userQuerySchema,
+ userSchema,
+ } from './users.schema';
+```
+adjust the options when the service is generated
+```js
+ app.use('users', new UserService(getOptions(app)), {
+ // A list of all methods this service exposes externally
+ methods: ['find', 'get', 'create', 'update', 'patch', 'remove'],
+ // You can add additional custom events to be sent to clients here
+ events: [],
+ docs: createSwaggerServiceOptions({
+ schemas: { userDataSchema, userQuerySchema, userSchema },
+ docs: {
+ // any options for service.docs can be added here
+ securities: ['find', 'get', 'update', 'patch', 'remove'],
+ }
+ }),
+ });
+```
+
+If you are using Typescript don't forget to add the docs property to the ServiceOptions interface
+which is described on the
+[Getting Started - Configure the documentation for a feathers service](/#/?id=configure-the-documentation-for-a-feathers-service)
diff --git a/docs/examples/index.md b/docs/examples/index.md
index f76b3ef..5b62197 100644
--- a/docs/examples/index.md
+++ b/docs/examples/index.md
@@ -10,3 +10,5 @@ It contains many configurations and can be start with `npm start` when feathers-
* [SwaggerUI](/examples/ui.md)
* [Prefixed Routes](/examples/prefixed_routes.md)
* [Custom Methods](/examples/custom_methods.md)
+* [Using Schemas of Feathersjs v5 (dove)](/examples/generated_service_v5.md)
+* [Authentication with Feathersjs v5 (dove)](/examples/authentication_v5.md)
diff --git a/docs/getting-started.md b/docs/getting-started.md
index c945a77..793b396 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -120,12 +120,51 @@ const app = express(feathers())
### Configure the documentation for a feathers service
-To customize the documentation of feathers service a docs property has to be added to a service before it is registered.
+To customize the documentation of feathers service a docs property has to be added. This can be done as property before the service is registered or as service path option.
There are many options please check out the [examples](examples/index.md) and the [API documentation](api.md#servicedocs) to get more details.
+#### **Service path option (TS)**
+The docs property can be set as [path service options](https://dove.feathersjs.com/api/application.html#use-path-service-options) introduced with feathers dove.
+
+```typescript
+import type { createSwaggerServiceOptions } from 'feathers-swagger';
+import {
+ messageDataSchema,
+ messageQuerySchema,
+ messageSchema,
+} from './message.schema';
+
+// ...
+
+app.use('message', new MessageService(), {
+ methods: ['find', 'get', 'create', 'update', 'patch', 'remove'],
+ events: [],
+ docs: createSwaggerServiceOptions({
+ schemas: { messageDataSchema, messageQuerySchema, messageSchema },
+ docs: { description: 'My custom service description' }
+ })
+});
+```
+
+To be able to set the docs property on the service options, the interface has to be adjusted in the `declarations.ts` of the project.
+
+```typescript
+import { ServiceSwaggerOptions } from 'feathers-swagger';
+
+// ...
+
+declare module '@feathersjs/feathers' {
+ interface ServiceOptions {
+ docs?: ServiceSwaggerOptions;
+ }
+}
+```
+
#### **Simple**
+The docs property can be set as property of a service instance before it is registered.
+
```js
// definition of service
@@ -169,6 +208,7 @@ To resolve, either manually define your model schemas or consider automated alte
* [Migrations for version 1](migrations/MIGRATIONS_v1.md)
* [Migrations for version 2](migrations/MIGRATIONS_v2.md)
+* [Migrations for version 3](migrations/MIGRATIONS_v3.md)
## License
diff --git a/docs/migrations/MIGRATIONS_v3.md b/docs/migrations/MIGRATIONS_v3.md
new file mode 100644
index 0000000..00acb5b
--- /dev/null
+++ b/docs/migrations/MIGRATIONS_v3.md
@@ -0,0 +1,30 @@
+## Migrations for Version 3 (from 2)
+
+Version 3.0.0 introduces some breaking changes to previous 2.x.x versions. These changes and ways to migrate to the new release will be described here.
+
+### Adjust the default schema / definition name of generated lists and pagination schemas
+
+#### Before
+Generated names were `${model}_list` and `${model}_pagination` and could not be adjusted.
+
+#### After
+Generated names will by default be `${model}List` and `${model}Pagination` but can be adjusted.
+
+To get the old behavior you can override the schemaNames generation (on service level) or as defaults.
+```js
+swagger({
+ specs: {
+ info: {
+ title: 'A test',
+ description: 'A description',
+ version: '1.0.0'
+ },
+ defaults: {
+ schemaNames: {
+ list: name => `${name}_list`,
+ pagination: name => `${name}_pagination`,
+ }
+ }
+ },
+})
+```
diff --git a/example/app.js b/example/app.js
index f78425e..571aeb4 100644
--- a/example/app.js
+++ b/example/app.js
@@ -20,6 +20,7 @@ const openApiV3Security = require('./openapi-v3/security');
const openApiV3CustomMethods = require('./openapi-v3/customMethods');
const openApiV3Multi = require('./openapi-v3/multi');
const openApiV3IdNames = require('./openapi-v3/idNames');
+const openApiV3DoveSchemas = require('./openapi-v3/doveSchemas');
const app = express(feathers())
.use(express.json())
@@ -52,9 +53,11 @@ const app = express(feathers())
.configure(openApiV3CustomMethods)
.configure(openApiV3Multi)
.configure(openApiV3IdNames)
+ .configure(openApiV3DoveSchemas)
;
-console.log('Simple app with multiple feathers-swagger examples running on http://localhost:3030/');
+const port = process.env.PORT || 3030;
+console.log(`Simple app with multiple feathers-swagger examples running on http://localhost:${port}/`);
-app.listen(process.env.PORT || 3030);
+app.listen(port);
diff --git a/example/docs.html b/example/docs.html
index 90e51eb..a274847 100644
--- a/example/docs.html
+++ b/example/docs.html
@@ -71,7 +71,7 @@