From 438ec8e292963b7cde46e1944f9a7bd65eb2b666 Mon Sep 17 00:00:00 2001 From: Ashot Nazaryan Date: Tue, 16 Jan 2024 23:17:59 -0800 Subject: [PATCH] feat: allow a service to be marked as multipart --- lib/utils.js | 4 ++-- lib/v3/generator.js | 32 +++++++++++++++++++------------- test/utils.test.js | 6 ++++++ types/index.d.ts | 1 + 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/lib/utils.js b/lib/utils.js index a8625cb..c948a97 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -165,8 +165,8 @@ function determineSchemaPrefix (schemas) { return undefined; } -exports.createSwaggerServiceOptions = function createSwaggerServiceOptions ({ schemas, docs, transformSchema }) { - const serviceDocs = { schemas: {}, refs: {} }; +exports.createSwaggerServiceOptions = function createSwaggerServiceOptions ({ schemas, docs, transformSchema, multipart = false }) { + const serviceDocs = { schemas: {}, refs: {}, multipart }; const transformSchemaFn = transformSchema || exports.defaultTransformSchema; let unspecificSchemas; diff --git a/lib/v3/generator.js b/lib/v3/generator.js index c357fec..ed6879b 100644 --- a/lib/v3/generator.js +++ b/lib/v3/generator.js @@ -28,12 +28,13 @@ function filterParameter (refs, ref = 'filterParameter', properties = {}) { }; } -function jsonSchemaRef (ref) { +function jsonSchemaRef (ref, multipart = false) { + const contentType = multipart ? 'multipart/form-data' : 'application/json'; if (typeof ref === 'object' && ref.refs) { const { refs, type, ...rest } = ref; return { - 'application/json': { + [contentType]: { schema: { [type]: refs.map(innerRef => ({ $ref: `#/components/schemas/${innerRef}` })), ...rest @@ -43,7 +44,7 @@ function jsonSchemaRef (ref) { } return { - 'application/json': { + [contentType]: { schema: { $ref: `#/components/schemas/${ref}` } @@ -215,14 +216,15 @@ class OpenApiV3Generator extends AbstractApiGenerator { security: utils.security('get', securities, security) }; }, - create ({ tags, security, securities, refs, multiOperations }) { + create ({ tags, security, securities, refs, multiOperations, service }) { + const multipart = service.docs.multipart; const multi = multiOperations.includes('create'); return { tags, description: 'Creates a new resource with data.', requestBody: { required: true, - content: multi ? jsonSchemaRef(refs.createMultiRequest) : jsonSchemaRef(refs.createRequest) + content: multi ? jsonSchemaRef(refs.createMultiRequest, multipart) : jsonSchemaRef(refs.createRequest, multipart) }, responses: { 201: { @@ -239,14 +241,15 @@ class OpenApiV3Generator extends AbstractApiGenerator { security: utils.security('create', securities, security) }; }, - update ({ tags, modelName, idName, idType, security, securities, refs }) { + update ({ tags, modelName, idName, idType, security, securities, refs, service }) { + const multipart = service.docs.multipart; return { tags, description: 'Updates the resource identified by id using data.', parameters: idPathParameters(idName, idType, `ID of ${modelName} to update`), requestBody: { required: true, - content: jsonSchemaRef(refs.updateRequest) + content: jsonSchemaRef(refs.updateRequest, multipart) }, responses: { 200: { @@ -266,14 +269,15 @@ class OpenApiV3Generator extends AbstractApiGenerator { security: utils.security('update', securities, security) }; }, - updateMulti ({ tags, security, securities, refs }) { + updateMulti ({ tags, security, securities, refs, service }) { + const multipart = service.docs.multipart; return { tags, description: 'Updates multiple resources.', parameters: [], requestBody: { required: true, - content: jsonSchemaRef(refs.updateMultiRequest) + content: jsonSchemaRef(refs.updateMultiRequest, multipart) }, responses: { 200: { @@ -290,14 +294,15 @@ class OpenApiV3Generator extends AbstractApiGenerator { security: utils.security('updateMulti', securities, security) }; }, - patch ({ tags, modelName, idName, idType, security, securities, refs }) { + patch ({ tags, modelName, idName, idType, security, securities, refs, service }) { + const multipart = service.docs.multipart; return { tags, description: 'Updates the resource identified by id using data.', parameters: idPathParameters(idName, idType, `ID of ${modelName} to update`), requestBody: { required: true, - content: jsonSchemaRef(refs.patchRequest) + content: jsonSchemaRef(refs.patchRequest, multipart) }, responses: { 200: { @@ -317,14 +322,15 @@ class OpenApiV3Generator extends AbstractApiGenerator { security: utils.security('patch', securities, security) }; }, - patchMulti ({ tags, security, securities, refs }) { + patchMulti ({ tags, security, securities, refs, service }) { + const multipart = service.docs.multipart; return { tags, description: 'Updates multiple resources queried by given filters.', parameters: [filterParameter(refs)], requestBody: { required: true, - content: jsonSchemaRef(refs.patchMultiRequest) + content: jsonSchemaRef(refs.patchMultiRequest, multipart) }, responses: { 200: { diff --git a/test/utils.test.js b/test/utils.test.js index 9f9d7e8..2a7856a 100644 --- a/test/utils.test.js +++ b/test/utils.test.js @@ -213,6 +213,7 @@ describe('util tests', () => { }); expect(result).to.deep.equal({ + multipart: false, schemas: { Message: without$IdAndTypeBoxProperties(messageSchema), MessageData: without$IdAndTypeBoxProperties(messageDataSchema), @@ -245,6 +246,7 @@ describe('util tests', () => { }); expect(result).to.deep.equal({ + multipart: false, schemas: { Message: without$IdAndTypeBoxProperties(messageSchema), MessageData: without$IdAndTypeBoxProperties(messageDataSchema), @@ -276,6 +278,7 @@ describe('util tests', () => { }); expect(result).to.deep.equal({ + multipart: false, description: 'My description', refs: { createResponse: 'MySchema' }, schemas: { @@ -289,6 +292,7 @@ describe('util tests', () => { const result = createSwaggerServiceOptions({ schemas: { patchRequest: messageDataSchema } }); expect(result).to.deep.equal({ + multipart: false, schemas: { MessageData: without$IdAndTypeBoxProperties(messageDataSchema) }, @@ -302,6 +306,7 @@ describe('util tests', () => { const result = createSwaggerServiceOptions({ schemas: { getResponse: topicSchema } }); expect(result).to.deep.equal({ + multipart: false, schemas: { Topic: { type: 'object', @@ -353,6 +358,7 @@ describe('util tests', () => { }); expect(result).to.deep.equal({ + multipart: false, schemas: { SimpleIdObject: { destroyed: true diff --git a/types/index.d.ts b/types/index.d.ts index f581515..0dc6fe2 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -309,6 +309,7 @@ declare namespace feathersSwagger { }, docs?: ServiceSwaggerOptions, transformSchema?: (schema: Schema) => Record, + multipart?: boolean }): ServiceSwaggerOptions; function defaultTransformSchema(schema: Schema): Record;