Add query validator to check for field existence

This commit is contained in:
rijkvanzanten
2020-06-16 17:30:25 -04:00
parent 8d5e7ef33a
commit 45101b6f40
8 changed files with 62 additions and 4 deletions

View File

@@ -3,11 +3,13 @@ import logger from './logger';
export enum ErrorCode {
NOT_FOUND = 'NOT_FOUND',
FIELD_NOT_FOUND = 'FIELD_NOT_FOUND',
INTERNAL_SERVER_ERROR = 'INTERNAL_SERVER_ERROR',
}
enum HTTPStatus {
NOT_FOUND = 404,
FIELD_NOT_FOUND = 400,
INTERNAL_SERVER_ERROR = 500,
}

View File

@@ -1,5 +1,5 @@
import pino from "pino";
import pino from 'pino';
const logger = pino();
const logger = pino({ level: process.env.LOG_LEVEL || 'info' });
export default logger;

View File

@@ -8,7 +8,10 @@ const collectionExists: RequestHandler = asyncHandler(async (req, res, next) =>
const exists = await database.schema.hasTable(req.params.collection);
if (exists) return next();
if (exists) {
res.locals.collection = req.params.collection;
return next();
}
throw new APIError(ErrorCode.NOT_FOUND, `Collection "${req.params.collection}" doesn't exist.`);
});

View File

@@ -5,6 +5,7 @@
import { RequestHandler } from 'express';
import { Query } from '../types/query';
import logger from '../logger';
const sanitizeQuery: RequestHandler = (req, res, next) => {
if (!req.query) return;

View File

@@ -0,0 +1,47 @@
/**
* Validates query parameters.
* We'll check if all fields you're trying to access exist
*
* This has to be run after sanitizeQuery
*/
import { RequestHandler } from 'express';
import { Query } from '../types/query';
import { hasField } from '../services/schema';
import asyncHandler from 'express-async-handler';
import APIError, { ErrorCode } from '../error';
const validateQuery: RequestHandler = asyncHandler(async (req, res, next) => {
if (!res.locals.collection) return next();
if (!res.locals.query) return next();
const query: Query = res.locals.query;
const fieldsToCheck = new Set<string>();
if (query.fields) {
query.fields.forEach((field) => fieldsToCheck.add(field));
}
try {
await Promise.all(
Array.from(fieldsToCheck).map(
(field) =>
new Promise(async (resolve, reject) => {
const exists = await hasField(res.locals.collection, field);
if (exists) return resolve();
return reject({ collection: res.locals.collection, field: field });
})
)
);
} catch ({ collection, field }) {
throw new APIError(
ErrorCode.FIELD_NOT_FOUND,
`Field "${field}" doesn't exist in "${collection}"`
);
}
return next();
});
export default validateQuery;

View File

@@ -3,6 +3,7 @@ import asyncHandler from 'express-async-handler';
import { createItem, readItems, readItem, updateItem, deleteItem } from '../services/items';
import sanitizeQuery from '../middleware/sanitize-query';
import collectionExists from '../middleware/collection-exists';
import validateQuery from '../middleware/validate-query';
const router = express.Router();
@@ -19,6 +20,7 @@ router.get(
'/:collection',
collectionExists,
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const records = await readItems(req.params.collection, res.locals.query);

View File

@@ -1,6 +1,5 @@
import database from '../database';
import { Query } from '../types/query';
import logger from '../logger';
export const createItem = async (
collection: string,

View File

@@ -3,3 +3,7 @@ import database from '../database';
export const hasCollection = async (collection: string) => {
return await database.schema.hasTable(collection);
};
export const hasField = async (collection: string, field: string) => {
return await database.schema.hasColumn(collection, field);
};