validator.js•4.38 kB
/**
* Request validation middleware
* Validates request data against schemas
*/
const Joi = require('joi');
const { ValidationError } = require('../utils/errorTypes');
const logger = require('../utils/logger');
/**
* Create validation middleware
* @param {Object} schema - Joi validation schema
* @param {string} property - Request property to validate (body, params, query)
* @returns {Function} - Validation middleware
*/
const validate = (schema, property = 'body') => {
return (req, res, next) => {
const data = req[property];
const { error, value } = schema.validate(data, {
abortEarly: false,
stripUnknown: true
});
if (error) {
// Format validation errors
const errors = {};
error.details.forEach((detail) => {
const path = detail.path.join('.');
errors[path] = detail.message;
});
logger.debug(`Validation error for ${req.method} ${req.originalUrl}: ${JSON.stringify(errors)}`);
// Return validation error
return next(new ValidationError('Validation failed', errors));
}
// Replace request data with validated data
req[property] = value;
next();
};
};
/**
* Common validation schemas
*/
const schemas = {
// User schemas
user: {
create: Joi.object({
name: Joi.string().required(),
email: Joi.string().email().required(),
facebookId: Joi.string().required()
})
},
// Campaign schemas
campaign: {
create: Joi.object({
name: Joi.string().required(),
adAccountId: Joi.string().required(),
objective: Joi.string().required(),
status: Joi.string().valid('ACTIVE', 'PAUSED', 'DELETED', 'ARCHIVED').default('PAUSED'),
spendCap: Joi.number().min(0),
dailyBudget: Joi.number().min(0),
lifetimeBudget: Joi.number().min(0),
startTime: Joi.date(),
endTime: Joi.date().greater(Joi.ref('startTime'))
}),
update: Joi.object({
name: Joi.string(),
status: Joi.string().valid('ACTIVE', 'PAUSED', 'DELETED', 'ARCHIVED'),
spendCap: Joi.number().min(0),
dailyBudget: Joi.number().min(0),
lifetimeBudget: Joi.number().min(0),
startTime: Joi.date(),
endTime: Joi.date().greater(Joi.ref('startTime'))
})
},
// Ad Set schemas
adSet: {
create: Joi.object({
name: Joi.string().required(),
campaignId: Joi.string().required(),
status: Joi.string().valid('ACTIVE', 'PAUSED', 'DELETED', 'ARCHIVED').default('PAUSED'),
targeting: Joi.object().required(),
optimization: Joi.string().required(),
bidStrategy: Joi.string().required(),
budget: Joi.number().min(0).required(),
startTime: Joi.date(),
endTime: Joi.date().greater(Joi.ref('startTime'))
}),
update: Joi.object({
name: Joi.string(),
status: Joi.string().valid('ACTIVE', 'PAUSED', 'DELETED', 'ARCHIVED'),
targeting: Joi.object(),
optimization: Joi.string(),
bidStrategy: Joi.string(),
budget: Joi.number().min(0),
startTime: Joi.date(),
endTime: Joi.date().greater(Joi.ref('startTime'))
})
},
// Ad schemas
ad: {
create: Joi.object({
name: Joi.string().required(),
adSetId: Joi.string().required(),
status: Joi.string().valid('ACTIVE', 'PAUSED', 'DELETED', 'ARCHIVED').default('PAUSED'),
creativeId: Joi.string(),
creative: Joi.object()
}),
update: Joi.object({
name: Joi.string(),
status: Joi.string().valid('ACTIVE', 'PAUSED', 'DELETED', 'ARCHIVED'),
creativeId: Joi.string(),
creative: Joi.object()
})
},
// Analytics schemas
analytics: {
query: Joi.object({
startDate: Joi.date().required(),
endDate: Joi.date().greater(Joi.ref('startDate')).required(),
metrics: Joi.array().items(Joi.string()).default(['impressions', 'clicks', 'spend']),
breakdown: Joi.string(),
limit: Joi.number().integer().min(1).max(1000).default(100)
})
},
// ID parameter schema
idParam: Joi.object({
id: Joi.string().required()
}),
// Pagination schema
pagination: Joi.object({
page: Joi.number().integer().min(1).default(1),
limit: Joi.number().integer().min(1).max(100).default(20),
sort: Joi.string(),
fields: Joi.string()
})
};
module.exports = {
validate,
schemas
};