Add API validator middleware

This commit is contained in:
Alexander Ungar 2023-03-21 23:28:41 +01:00
parent 4d72d8035f
commit 06e3fafe15
7 changed files with 31 additions and 11 deletions

View file

@ -256,7 +256,7 @@ components:
example: 23.94
date:
type: string
format: date
format: date-time
NewTransaction:
type: object
description: A new transaction to be created
@ -275,4 +275,4 @@ components:
example: 23.94
date:
type: string
format: date
format: date-time

View file

@ -26,6 +26,7 @@
"express": "^4.18.2",
"express-async-errors": "^3.1.1",
"express-async-handler": "^1.2.0",
"express-openapi-validator": "^5.0.3",
"express-winston": "^4.2.0",
"helmet": "^6.0.1",
"http-status-codes": "^2.2.0",

View file

@ -9,9 +9,10 @@ import BudgetMongoRepository from "./repository/budget/mongo/budgetMongoReposito
import BudgetSummaryMongoRepository from "./repository/budget/mongo/budgetSummaryMongoRepository.js";
import TransactionService from "./usecase/transaction/transactionService.js";
import TransactionMongoRepository from "./repository/transaction/mongo/TransactionMongoRepository.js";
import OpenApiValidator from "express-openapi-validator";
const app = express();
const API_ROOT = "/api";
const API_ROOT = "/";
app.use(expressLogger);
app.use(express.json());
@ -21,6 +22,14 @@ if (environment.isProd) {
app.use(helmet());
}
app.use(
OpenApiValidator.middleware({
apiSpec: new URL(`../api/my-finance-pal.yml`, import.meta.url).pathname,
validateRequests: true,
validateResponses: true,
})
);
const budgetUseCases = BudgetService(
BudgetSummaryMongoRepository(),
BudgetMongoRepository()

View file

@ -1,7 +1,7 @@
import type * as Http from "http";
import logger from "../logging/logger.js";
import * as util from "util";
import { NextFunction, type Request, type Response } from "express";
import { type NextFunction, type Request, type Response } from "express";
let httpServerRef: Http.Server;
@ -103,5 +103,8 @@ export const errorHandler = (
}
// ✅ Best Practice: Pass all error to a centralized error handler so they get treated equally
handleError(err);
res.status((err as AppError).HTTPStatus ?? 500).end();
res
.status((err as AppError).HTTPStatus ?? 500)
.json({ message: err.message, errors: (err as any).errors })
.end();
};

View file

@ -14,7 +14,7 @@ const budgetSummarySchema = new mongoose.Schema<BudgetSummaryEntity>(
endDate: Types.Date,
transactions: [transactionSchema],
},
{ strict: true, timestamps: true }
{ strict: true, timestamps: true, versionKey: false }
);
export default budgetSummarySchema;

View file

@ -4,7 +4,7 @@ import {
type NewBudget,
} from "../../../domain/budget.js";
import Limit from "../../../domain/limit.js";
import { toDate } from "../../../util/date.js";
import { toDate, toIsoDate } from "../../../util/date.js";
import {
type BudgetDto,
type BudgetSummaryDto,
@ -27,8 +27,8 @@ export const BudgetDtoConverter = {
limit: domain.limit.amount,
spent: domain.spent,
name: domain.name,
startDate: domain.startDate?.toISOString(),
endDate: domain.endDate?.toISOString(),
startDate: toIsoDate(domain.startDate),
endDate: toIsoDate(domain.endDate),
}),
};
@ -38,8 +38,8 @@ export const BudgetSummaryDtoConverter = {
limit: domain.limit.amount,
spent: domain.spent,
name: domain.name,
startDate: domain.startDate?.toISOString(),
endDate: domain.endDate?.toISOString(),
startDate: toIsoDate(domain.startDate),
endDate: toIsoDate(domain.endDate),
transactions: domain.transactions.map(TransactionDtoConverter.toDto),
}),
};

View file

@ -3,3 +3,10 @@ export const toDate = (isoString?: string): Date | undefined => {
return new Date(isoString);
}
};
export const toIsoDate = (date?: Date): string | undefined => {
if (date !== null && date !== undefined) {
const isoDateTime = date.toISOString();
return isoDateTime.substring(0, isoDateTime.indexOf("T"));
}
};