UNPKG

@getanthill/datastore

Version:

Event-Sourced Datastore

236 lines (190 loc) 5.63 kB
import type { NextFunction, Request, Response } from 'express'; import type { ModelConfig, Services } from '../../typings'; import type { OpenAPIMiddleware } from '../middleware'; export async function updateApiDefinition( services: Services, openApi?: OpenAPIMiddleware, ) { const { config, models } = services; if ( config.mode === 'development' || config.features.api.updateSpecOnModelsChange === true ) { await models.reset().reload(true); await openApi?.update(); } } export function getModels(services: Services) { return async (req: Request, res: Response, next: NextFunction) => { // @ts-ignore if (res.body) { return next(); } try { services.metrics.incrementApiAdminGetModels(); const response: { [key: string]: ModelConfig } = {}; const model = req.query.model; for (const [modelName, Model] of services.models.MODELS.entries()) { if (services.models.isInternalModel(modelName) === true) { continue; } if (model && modelName !== model) { continue; } response[modelName] = Model.getModelConfig(); } res.json(response); } catch (err: any) { next(err); } }; } export function getGraph(services: Services) { return async (req: Request, res: Response, next: NextFunction) => { // @ts-ignore if (res.body) { return next(); } try { services.metrics.incrementApiAdminGetGraph(); const graph = services.models.getGraph(req.query); res.json(graph); } catch (err: any) { next(err); } }; } export function getSchema(services: Services) { return async (req: Request, res: Response, next: NextFunction) => { // @ts-ignore if (res.body) { return next(); } try { services.metrics.incrementApiAdminGetSchema(); const Model = services.models.getModel(req.params.model); /** * Adding the correlation field to the response headers * @todo need to apply this to every request and in the API documentation */ res.set({ 'correlation-field': Model.getModelConfig().correlation_field, }); res.json(Model.getOriginalSchema()); } catch (err: any) { if (err.message === 'Invalid Model') { err.status = 400; return next(err); } next(err); } }; } export function create(services: Services, openApi?: OpenAPIMiddleware) { return async (req: Request, res: Response, next: NextFunction) => { // @ts-ignore if (res.body) { return next(); } try { const modelConfig = req.body; services.metrics.incrementApiAdminCreateModel({ model: modelConfig.name, }); const internalModel = await services.models.createModel(modelConfig); await updateApiDefinition(services, openApi); return res.json(internalModel.state); } catch (err: any) { if (err.message === 'Event schema validation error') { err.status = 400; return next(err); } if (err.message === 'Model already exists') { err.status = 409; return next(err); } next(err); } }; } export function update(services: Services, openApi?: OpenAPIMiddleware) { return async (req: Request, res: Response, next: NextFunction) => { // @ts-ignore if (res.body) { return next(); } try { const modelConfig = req.body; services.metrics.incrementApiAdminUpdateModel({ model: modelConfig.name, }); const updatedModel = await services.models.updateModel( req.params.model, modelConfig, ); await updateApiDefinition(services, openApi); return res.json(updatedModel.state); } catch (err: any) { if (err.message === 'Invalid Model') { err.status = 400; return next(err); } if (err.message === 'Event schema validation error') { err.status = 400; return next(err); } next(err); } }; } export function createModelIndexes(services: Services) { return async (req: Request, res: Response, next: NextFunction) => { // @ts-ignore if (res.body) { return next(); } try { const modelConfig = 'indexes' in req.body ? req.body : services.models.getModel(req.params.model).getModelConfig(); services.metrics.incrementApiAdminUpdateModelIndexes({ model: req.params.model, }); const modelIndexes = await services.models.createModelIndexes({ name: req.params.model, ...modelConfig, }); res.json(modelIndexes); } catch (err: any) { if (err.message === 'Invalid Model') { err.status = 400; return next(err); } next(err); } }; } export function rotateEncryptionKeys(services: Services) { return async (req: Request, res: Response, next: NextFunction) => { // @ts-ignore if (res.body) { return next(); } try { services.metrics.incrementApiAdminRotateEncryptionKeys(); res.status(202).end(); const onlyModels = req.query.models as string[] | undefined; services.telemetry.logger.info('[admin] Encryption key rotation started'); await services.models.rotateEncryptionKey(onlyModels); services.telemetry.logger.info('[admin] Encryption key rotation ended'); } catch (err: any) { services.telemetry.logger.error( '[admin] Encryption key rotation failed', { err, }, ); } }; }