redis-smq-rest-api
Version:
A RESTful API for RedisSMQ
156 lines • 6.73 kB
JavaScript
import { readFileSync } from 'fs';
import { constants } from '../../config/constants.js';
import { EControllerRequestPayload } from '../controller/types/index.js';
import { RouterRequestValidationError } from '../router/errors/RouterRequestValidationError.js';
import { RouterResponseValidationError } from '../router/errors/RouterResponseValidationError.js';
import { ajv } from './validator.js';
const payloadSources = [
EControllerRequestPayload.PATH,
EControllerRequestPayload.QUERY,
EControllerRequestPayload.BODY,
];
export function SchemaGenerator() {
const schema = readFileSync(constants.jsonSchemaPath);
const { definitions = {} } = JSON.parse(schema.toString());
const getDefinition = (name) => {
const def = definitions[name];
if (!def || typeof def === 'boolean')
throw new Error(`Schema ${name} not found.`);
return def;
};
const getRequestSchema = (controllerName, payloadSource) => {
const cName = `${controllerName[0].toUpperCase()}${controllerName.slice(1)}`;
const payload = EControllerRequestPayload[payloadSource];
const pName = payload[0].toUpperCase() + payload.slice(1).toLowerCase();
const type = `${cName}Request${pName}DTO`;
return getDefinition(type);
};
const getResponseSchema = (controllerName) => {
const cName = `${controllerName[0].toUpperCase()}${controllerName.slice(1)}`;
const type = `${cName}ResponseDTO`;
const schema = getDefinition(type);
return getResponseMap(schema);
};
const getResponseMap = (schema) => {
const responses = new Map();
const handleResponse = (responseSchema) => {
if (typeof responseSchema === 'object' &&
responseSchema.type === 'array' &&
responseSchema.minItems === 2 &&
Array.isArray(responseSchema.items)) {
const [status, message] = responseSchema.items;
if (typeof message === 'object' &&
typeof status === 'object' &&
status.type === 'number' &&
typeof status.const === 'number') {
const codeStr = String(status.const);
const messageStr = String(message.const);
if (['4', '5'].includes(codeStr[0])) {
responses.set(messageStr, {
responseCode: status.const,
schema: {
type: 'object',
properties: {
error: {
type: 'object',
properties: {
code: status,
message: message,
details: {
type: 'object',
},
},
required: ['code', 'message', 'details'],
additionalProperties: false,
},
},
required: ['error'],
additionalProperties: false,
},
});
}
else if (codeStr[0] === '2') {
const schema = status.const === 204
? message
: {
type: 'object',
properties: {
data: message,
},
required: ['data'],
additionalProperties: false,
};
responses.set('OK', {
responseCode: status.const,
schema,
});
}
else
throw new Error();
}
else
throw new Error();
}
else
throw new Error('Expected a JSON Schema type');
};
if (schema.anyOf) {
for (const responseSchema of schema.anyOf)
handleResponse(responseSchema);
}
else
handleResponse(schema);
return responses;
};
return {
getDefinitions() {
return definitions;
},
getRequestSchemas(controllerName, requestPayloadSource) {
return payloadSources.reduce((accumulator, currentValue) => {
const schemaDefinition = requestPayloadSource.includes(currentValue)
? getRequestSchema(controllerName, currentValue)
: {
type: 'object',
additionalProperties: false,
};
accumulator.set(currentValue, schemaDefinition);
return accumulator;
}, new Map());
},
getRequestValidators(map) {
return payloadSources.reduce((accumulator, currentValue) => {
const schema = map.get(currentValue);
if (!schema)
throw new Error();
const validator = ajv.compile(schema);
const validatorFn = (data) => {
const isValid = validator(data);
if (!isValid && validator.errors) {
throw new RouterRequestValidationError(validator.errors);
}
};
accumulator.set(currentValue, validatorFn);
return accumulator;
}, new Map());
},
getResponseSchemas(controllerName) {
return getResponseSchema(controllerName);
},
getResponseValidators(map) {
const m = new Map();
map.forEach((value, key) => {
const validator = ajv.compile(value.schema);
const validatorFn = (data) => {
const isValid = validator(data);
if (!isValid && validator.errors) {
throw new RouterResponseValidationError(validator.errors);
}
};
m.set(key, validatorFn);
});
return m;
},
};
}
//# sourceMappingURL=schema-generator.js.map