Skip to content

Commit 321ef1f

Browse files
committed
feat!(schema): add possibility to consume dove json schemas
breaking: change the default naming of list and pagination schemas to be camel case
1 parent 75b7e7b commit 321ef1f

35 files changed

+5203
-3331
lines changed

docs/_sidebar.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
* Migrations
66
* * [Migrations for Version 1](/migrations/MIGRATIONS_v1.md)
77
* * [Migrations for Version 2](/migrations/MIGRATIONS_v2.md)
8+
* * [Migrations for version 3](/migrations/MIGRATIONS_v3.md)

docs/api.md

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ __Options:__
4848
- `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
4949
- `getOperationsRefs(model, service)` - Function to generate refs that the methods for operations will consume, see service.docs.refs option
5050
- `schemasGenerator(service, model, modelName, schemas)` - Function to generate the json schemas for a service
51+
- `schemaNames`
52+
- `list(model)` - function to return the default name for the list schema, defaults to `${model}List` if not provided
53+
- `pagination(model)` - function to return the default name for the list schema, defaults to `${model}Pagination` if not provided
5154
- `operationGenerators` - Generator functions to fully customize specification generation for operations. To disable the generation of a method return false.
5255
- `find`|`get`|`create`|`update`|`patch`|`remove` - Generator function for the specific operation.
5356
- `updateMulti`|`patchMulti`|`removeMulti` - Generator function for the "multi mode" version of the specific operation
@@ -121,10 +124,50 @@ __Options:__
121124
- `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.
122125
- `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.
123126
- `all` - Custom (parts of the) specification for all operations.
124-
- `refs` (*optional*) - Change the refs that are used for different operations: findResponse, getResponse, createRequest, createResponse, updateRequest, updateResponse, patchRequest, patchResponse, removeResponse, {customMethodName[Request|Response]}
127+
- `refs` (*optional*) - Object with mapping of refs that are used for different operations, by setting the schema name
128+
- `findResponse`
129+
- `getResponse`
130+
- `createRequest`
131+
- `createResponse`
132+
- `createMultiRequest` - only with `openApiVersion` 3
133+
- `createMultiResponse` - only with `openApiVersion` 3
134+
- `updateRequest`
135+
- `updateResponse`
136+
- `updateMultiRequest`
137+
- `updateMultiResponse`
138+
- `patchRequest`
139+
- `patchResponse`
140+
- `patchMultiRequest`
141+
- `patchMultiResponse`
142+
- `removeResponse`
143+
- `removeMultiResponse`
144+
- `filterParameter`
145+
- `sortParameter`
146+
- `queryParameters` - only with `openApiVersion` 3
147+
- `{customMethodName[Request|Response]}`
148+
- `schemaNames` (*optional*) - Adjust the automatic generation of schema names
149+
- `list(model)` - Function to return the name for the list schema, defaults to `${model}List` if not provided
150+
- `pagination(model)` - Function to return the name for the list schema, defaults to `${model}Pagination` if not provided
125151
- `pathParams` (*optional*) - Object with param name as key and the definition as value, should be used when using "global" path parameters
126152
- `overwriteTagSpec` (*optional*, default: `false`) - If tag is already defined in the specs, should be overwritten from this service
127153

154+
### `swagger.createSwaggerServiceOptions(options)`
155+
156+
Helper function to create a `service.docs` object, based on the provided schemas.
157+
Only the `schemas`, `refs` and `model` properties will be generated.
158+
159+
__Options:__
160+
- `schemas` - Object with TypeBox or json schemas
161+
- Provide the generated schemas with `xxxSchema`, `xxxDataSchema` and `xxxQuerySchema` naming schema
162+
- This will generate the `schemas` and `refs` and `model` based on the provided schemas
163+
- Provide any schema that has an `$id` with any name
164+
- This will just add the schema that can be consumed in refs or customized operations specifications
165+
- Provide any schema that has an `$id` with a ref as key, check `service.docs.refs` for allowed refs
166+
- This will add the schema and use it for the given ref
167+
- `docs` - Any service.docs options that will be merged into the resulting object and would overwrite anything that will be generated
168+
- `sanitizeSchema` - A function that sanitizes the schema from properties that are not allowed in an OpenApi specification.
169+
If not provided a default implementation will be used.
170+
128171
### Path support to update nested structures
129172

130173
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:
140183
- `path[-]`
141184
- `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)
142185

143-
### `swaggerUI.customMethod(verb, path)`
186+
### `swagger.customMethod(verb, path)`
144187

145188
To define the rest method of a custom method it has to be wrapped/annotated with `customMethod`.
146189
For Feathers 5 the custom method has to be added to the methods when registering the service.

docs/examples/_sidebar.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@
77
* * [SwaggerUI](/examples/ui.md)
88
* * [Prefixed Routes](/examples/prefixed_routes.md)
99
* * [Custom Methods](/examples/custom_methods.md)
10+
* * [Using Schemas of Feathersjs v5 (dove)](/examples/generated_service_v5.md)
11+
* * [Authentication with Feathersjs v5 (dove)](/examples/authentication_v5.md)

docs/examples/authentication_v5.md

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
### Example with feathers generated authentication on feathersjs v5 (dove) <!-- {docsify-ignore} -->
2+
3+
1. When you have generated the app with authentication you have to add some things to the initial
4+
specs when registering feathers swagger.
5+
6+
```typescript
7+
app.configure(
8+
swagger({
9+
specs: {
10+
info: {
11+
title: 'Feathers app with swagger with authentication',
12+
version: '1.0.0',
13+
description: '...',
14+
},
15+
components: {
16+
securitySchemes: {
17+
BearerAuth: {
18+
type: 'http',
19+
scheme: 'bearer',
20+
},
21+
},
22+
},
23+
security: [{ BearerAuth: [] }],
24+
},
25+
// other options ...
26+
}),
27+
);
28+
```
29+
30+
2. Add documentation to the authentication service (`src/authentication.ts`).
31+
This example shows local authentication.
32+
33+
```typescript
34+
import { AuthenticationService, JWTStrategy } from '@feathersjs/authentication';
35+
import { LocalStrategy } from '@feathersjs/authentication-local';
36+
import type { Application } from './declarations';
37+
import { ServiceSwaggerOptions } from '../../feathers-swagger';
38+
39+
declare module './declarations' {
40+
interface ServiceTypes {
41+
authentication: AuthenticationService;
42+
}
43+
}
44+
45+
declare module '@feathersjs/authentication' {
46+
class AuthenticationService {
47+
docs: ServiceSwaggerOptions;
48+
}
49+
}
50+
51+
export const authentication = (app: Application) => {
52+
const authentication = new AuthenticationService(app);
53+
54+
authentication.docs = {
55+
idNames: {
56+
remove: 'accessToken',
57+
},
58+
idType: 'string',
59+
securities: ['remove', 'removeMulti'],
60+
multi: ['remove'],
61+
schemas: {
62+
authRequest: {
63+
type: 'object',
64+
properties: {
65+
strategy: { type: 'string' },
66+
email: { type: 'string' },
67+
password: { type: 'string' },
68+
},
69+
},
70+
authResult: {
71+
type: 'object',
72+
properties: {
73+
accessToken: { type: 'string' },
74+
authentication: {
75+
type: 'object',
76+
properties: {
77+
strategy: { type: 'string' },
78+
},
79+
},
80+
payload: {
81+
type: 'object',
82+
properties: {}, // TODO
83+
},
84+
user: { $ref: '#/components/schemas/User' },
85+
},
86+
},
87+
},
88+
refs: {
89+
createRequest: 'authRequest',
90+
createResponse: 'authResult',
91+
removeResponse: 'authResult',
92+
removeMultiResponse: 'authResult',
93+
},
94+
operations: {
95+
remove: {
96+
description: 'Logout the currently logged in user',
97+
'parameters[0].description': 'accessToken of the currently logged in user',
98+
},
99+
removeMulti: {
100+
description: 'Logout the currently logged in user',
101+
parameters: [],
102+
},
103+
},
104+
};
105+
106+
authentication.register('jwt', new JWTStrategy());
107+
authentication.register('local', new LocalStrategy());
108+
109+
app.use('authentication', authentication);
110+
};
111+
```
112+
113+
3. Set the `security` option for `service.docs` like shown in
114+
[Using Schemas of Feathersjs v5 (dove)](/examples/generated_service_v5.md) for methods that are protected.
115+
If all methods are protected `all` can be used.
116+
117+
4. If you want to provide simple authentication usage on the SwaggerUI using Email/Username and Password,
118+
you can use the [Swagger UI Plugin ApiKeyAuthForm](https://github.com/Mairu/swagger-ui-apikey-auth-form).
119+
120+
Here is an example of an `openapi.ts` swagger configuration file, that can used with `api.configure()`;
121+
122+
```typescript
123+
import swagger, { FnSwaggerUiGetInitializerScript } from 'feathers-swagger';
124+
import type { Application } from './declarations';
125+
126+
const getSwaggerInitializerScript: FnSwaggerUiGetInitializerScript = ({ docsJsonPath, ctx }) => {
127+
const headers = ctx && ctx.headers;
128+
const basePath = headers!['x-forwarded-prefix'] ?? '';
129+
130+
// language=JavaScript
131+
return `
132+
window.onload = function () {
133+
var script = document.createElement('script');
134+
script.onload = function () {
135+
window.ui = SwaggerUIBundle({
136+
url: "${basePath}${docsJsonPath}",
137+
dom_id: '#swagger-ui',
138+
deepLinking: true,
139+
presets: [
140+
SwaggerUIBundle.presets.apis,
141+
SwaggerUIStandalonePreset,
142+
SwaggerUIApiKeyAuthFormPlugin,
143+
],
144+
plugins: [
145+
SwaggerUIBundle.plugins.DownloadUrl
146+
],
147+
layout: "StandaloneLayout",
148+
configs: {
149+
apiKeyAuthFormPlugin: {
150+
forms: {
151+
BearerAuth: {
152+
fields: {
153+
email: {
154+
type: 'text',
155+
label: 'E-Mail-Address',
156+
},
157+
password: {
158+
type: 'password',
159+
label: 'Password',
160+
},
161+
},
162+
authCallback(values, callback) {
163+
window.ui.fn.fetch({
164+
url: '/authentication',
165+
method: 'post',
166+
headers: {
167+
Accept: 'application/json',
168+
'Content-Type': 'application/json'
169+
},
170+
body: JSON.stringify({
171+
strategy: 'local',
172+
...values,
173+
}),
174+
}).then(function (response) {
175+
const json = JSON.parse(response.data);
176+
if (json.accessToken) {
177+
callback(null, json.accessToken);
178+
} else {
179+
callback('error while login');
180+
}
181+
}).catch(function (err) {
182+
console.log(err, Object.entries(err));
183+
callback('error while login');
184+
});
185+
},
186+
}
187+
},
188+
localStorage: {
189+
BearerAuth: {}
190+
}
191+
}
192+
}
193+
});
194+
};
195+
196+
script.src = '//cdn.jsdelivr.net/npm/@mairu/swagger-ui-apikey-auth-form@1/dist/swagger-ui-apikey-auth-form.js';
197+
document.head.appendChild(script)
198+
};
199+
`;
200+
};
201+
202+
export default (app: Application) => {
203+
// If you don't use custom methods this line can be removed
204+
app.configure(swagger.customMethodsHandler);
205+
206+
app.configure(
207+
swagger({
208+
specs: {
209+
info: {
210+
title: 'Example with Authentication',
211+
version: '1.0.0',
212+
description: 'Example with Authentication and SwaggerUI ApiKeyAuthForm plugin',
213+
},
214+
components: {
215+
securitySchemes: {
216+
BearerAuth: {
217+
type: 'http',
218+
scheme: 'bearer',
219+
},
220+
},
221+
},
222+
security: [{ BearerAuth: [] }],
223+
},
224+
ui: swagger.swaggerUI({ getSwaggerInitializerScript }),
225+
}),
226+
);
227+
};
228+
```
229+
230+
Here is a preview together with a user service from [Using Schemas of Feathersjs v5 (dove)](/examples/generated_service_v5.md):
231+
232+
233+
[filename](../swagger-ui/index.html?url=../examples/authentication_v5_plugin.json ':include class=swui-preview')

0 commit comments

Comments
 (0)