diff --git a/src/middlewares/openapi.multipart.ts b/src/middlewares/openapi.multipart.ts index 5871ccce..e868b300 100644 --- a/src/middlewares/openapi.multipart.ts +++ b/src/middlewares/openapi.multipart.ts @@ -20,51 +20,58 @@ export function multipart( ): OpenApiRequestHandler { const mult = multer(options.multerOpts); const Ajv = createRequestAjv(apiDoc, { ...options.ajvOpts }); - return (req, res, next) => { + return async (req, res, next) => { // TODO check that format: binary (for upload) else do not use multer.any() // use multer.none() if no binary parameters exist if (shouldHandle(Ajv, req)) { - mult.any()(req, res, (err) => { - if (err) { - next(error(req, err)); - } else { - // TODO: - // If a form parameter 'file' is defined to take file value, but the user provides a string value instead - // req.files will be empty and req.body.file will be populated with a string - // This will incorrectly PASS validation. - // Instead, we should return a 400 with an invalid type e.g. file expects a file, but found string. - // - // In order to support this, we likely need to inspect the schema directly to find the type. - // For example, if param with type: 'string', format: 'binary' is defined, we expect to see it in - // req.files. If it's not present we should throw a 400 - // - // This is a bit complex because the schema may be defined inline (easy) or via a $ref (complex) in which - // case we must follow the $ref to check the type. - - if (req.files) { - // to handle single and multiple file upload at the same time, let us this initialize this count variable - // for example { "files": 5 } - const count_by_fieldname = (req.files) - .map((file) => file.fieldname) - .reduce((acc, curr) => { - acc[curr] = (acc[curr] || 0) + 1; - return acc; - }, {}); - - // add file(s) to body - Object.entries(count_by_fieldname).forEach( - ([fieldname, count]: [string, number]) => { - // TODO maybe also check in the api doc if it is a single upload or multiple - const is_multiple = count > 1; - req.body[fieldname] = is_multiple - ? new Array(count).fill('') - : ''; - }, - ); - } - next(); - } - }); + try { + await new Promise((resolve, reject) => { + mult.any()(req, res, (err) => { + if (err) { + reject(error(req, err)); + } else { + // TODO: + // If a form parameter 'file' is defined to take file value, but the user provides a string value instead + // req.files will be empty and req.body.file will be populated with a string + // This will incorrectly PASS validation. + // Instead, we should return a 400 with an invalid type e.g. file expects a file, but found string. + // + // In order to support this, we likely need to inspect the schema directly to find the type. + // For example, if param with type: 'string', format: 'binary' is defined, we expect to see it in + // req.files. If it's not present we should throw a 400 + // + // This is a bit complex because the schema may be defined inline (easy) or via a $ref (complex) in which + // case we must follow the $ref to check the type. + + if (req.files) { + // to handle single and multiple file upload at the same time, let us this initialize this count variable + // for example { "files": 5 } + const count_by_fieldname = (req.files) + .map((file) => file.fieldname) + .reduce((acc, curr) => { + acc[curr] = (acc[curr] || 0) + 1; + return acc; + }, {}); + + // add file(s) to body + Object.entries(count_by_fieldname).forEach( + ([fieldname, count]: [string, number]) => { + // TODO maybe also check in the api doc if it is a single upload or multiple + const is_multiple = count > 1; + req.body[fieldname] = is_multiple + ? new Array(count).fill('') + : ''; + }, + ); + } + resolve(); + } + }); + }); + next() + } catch (error) { + next(error); + } } else { next(); }