(scope: 'read' | 'update' | 'delete')
| 5 | import { validateQuery } from '../utils/validate-query.js'; |
| 6 | |
| 7 | export const validateBatch = (scope: 'read' | 'update' | 'delete') => |
| 8 | asyncHandler(async (req, _res, next) => { |
| 9 | if (req.method.toLowerCase() === 'get') { |
| 10 | req.body = {}; |
| 11 | return next(); |
| 12 | } |
| 13 | |
| 14 | if (req.method.toLowerCase() !== 'search' && scope !== 'read' && req.singleton) { |
| 15 | return next(); |
| 16 | } |
| 17 | |
| 18 | if (!req.body) throw new InvalidPayloadError({ reason: 'Payload in body is required' }); |
| 19 | |
| 20 | if (['update', 'delete'].includes(scope) && Array.isArray(req.body)) { |
| 21 | return next(); |
| 22 | } |
| 23 | |
| 24 | // In reads, the query in the body should override the query params for searching |
| 25 | if (scope === 'read' && req.body.query) { |
| 26 | req.sanitizedQuery = await sanitizeQuery(req.body.query, req.schema, req.accountability); |
| 27 | |
| 28 | validateQuery(req.sanitizedQuery); |
| 29 | } |
| 30 | |
| 31 | // Every cRUD action has either keys or query |
| 32 | let batchSchema = Joi.object().keys({ |
| 33 | keys: Joi.array().items(Joi.alternatives(Joi.string(), Joi.number())), |
| 34 | query: Joi.object().unknown(), |
| 35 | }); |
| 36 | |
| 37 | if (['update', 'delete'].includes(scope)) { |
| 38 | batchSchema = batchSchema.xor('query', 'keys'); |
| 39 | } |
| 40 | |
| 41 | // In updates, we add a required `data` that holds the update payload if an array isn't used |
| 42 | if (scope === 'update') { |
| 43 | batchSchema = batchSchema.keys({ |
| 44 | data: Joi.object().unknown().required(), |
| 45 | }); |
| 46 | } |
| 47 | |
| 48 | const { error } = batchSchema.validate(req.body); |
| 49 | |
| 50 | if (error) { |
| 51 | throw new InvalidPayloadError({ reason: error.details[0]!.message }); |
| 52 | } |
| 53 | |
| 54 | return next(); |
| 55 | }); |
no test coverage detected