Add api validations.

This commit is contained in:
Brian Cao 2023-08-19 22:23:15 -07:00
parent 7d5a24044a
commit 7a7233ead4
41 changed files with 690 additions and 180 deletions

View file

@ -1,19 +1,20 @@
import redis from '@umami/redis-client';
import cors from 'cors';
import debug from 'debug';
import { getAuthToken, parseShareToken } from 'lib/auth';
import { ROLES } from 'lib/constants';
import { isUuid, secret } from 'lib/crypto';
import { findSession } from 'lib/session';
import {
createMiddleware,
unauthorized,
badRequest,
createMiddleware,
parseSecureToken,
tooManyRequest,
unauthorized,
} from 'next-basics';
import debug from 'debug';
import cors from 'cors';
import redis from '@umami/redis-client';
import { findSession } from 'lib/session';
import { getAuthToken, parseShareToken } from 'lib/auth';
import { secret, isUuid } from 'lib/crypto';
import { ROLES } from 'lib/constants';
import { getUserById } from '../queries';
import { NextApiRequestCollect } from 'pages/api/send';
import { getUserById } from '../queries';
import { NextApiRequestQueryBody } from './types';
const log = debug('umami:middleware');
@ -75,3 +76,15 @@ export const useAuth = createMiddleware(async (req, res, next) => {
next();
});
export const useValidate = createMiddleware(async (req: any, res, next) => {
try {
const { yup } = req as NextApiRequestQueryBody;
yup[req.method].validateSync({ ...req.query, ...req.body });
} catch (e: any) {
return badRequest(res, e.message);
}
next();
});

View file

@ -5,11 +5,13 @@ import {
EVENT_TYPE,
KAFKA_TOPIC,
REPORT_FILTER_TYPES,
REPORT_TYPES,
ROLES,
TEAM_FILTER_TYPES,
USER_FILTER_TYPES,
WEBSITE_FILTER_TYPES,
} from './constants';
import * as yup from 'yup';
type ObjectValues<T> = T[keyof T];
@ -18,6 +20,8 @@ export type Role = ObjectValues<typeof ROLES>;
export type EventType = ObjectValues<typeof EVENT_TYPE>;
export type DynamicDataType = ObjectValues<typeof DATA_TYPE>;
export type KafkaTopic = ObjectValues<typeof KAFKA_TOPIC>;
export type ReportType = ObjectValues<typeof REPORT_TYPES>;
export type ReportSearchFilterType = ObjectValues<typeof REPORT_FILTER_TYPES>;
export type UserSearchFilterType = ObjectValues<typeof USER_FILTER_TYPES>;
export type WebsiteSearchFilterType = ObjectValues<typeof WEBSITE_FILTER_TYPES>;
@ -47,8 +51,8 @@ export interface ReportSearchFilter extends SearchFilter<ReportSearchFilterType>
export interface SearchFilter<T> {
filter?: string;
filterType?: T;
pageSize?: number;
page?: number;
pageSize: number;
page: number;
orderBy?: string;
}
@ -76,11 +80,19 @@ export interface Auth {
};
}
export interface YupRequest {
GET?: yup.ObjectSchema<any>;
POST?: yup.ObjectSchema<any>;
PUT?: yup.ObjectSchema<any>;
DELETE?: yup.ObjectSchema<any>;
}
export interface NextApiRequestQueryBody<TQuery = any, TBody = any> extends NextApiRequest {
auth?: Auth;
query: TQuery & { [key: string]: string | string[] };
body: TBody;
headers: any;
yup: YupRequest;
}
export interface NextApiRequestAuth extends NextApiRequest {
@ -168,7 +180,6 @@ export interface RealtimeUpdate {
export interface DateRange {
startDate: Date;
endDate: Date;
unit: string;
value: string;
}

19
lib/yup.ts Normal file
View file

@ -0,0 +1,19 @@
import * as yup from 'yup';
export function getDateRangeValidation() {
return {
startAt: yup.number().integer().required(),
endAt: yup.number().integer().moreThan(yup.ref('startAt')).required(),
};
}
// ex: /funnel|insights|retention/i
export function getFilterValidation(matchRegex) {
return {
filter: yup.string(),
filterType: yup.string().matches(matchRegex),
pageSize: yup.number().integer().positive().max(200),
page: yup.number().integer().positive(),
orderBy: yup.string(),
};
}