feature(api): add rate limiter

This commit is contained in:
Carl-Gerhard Lindesvärd
2024-10-07 10:33:50 +02:00
parent 2a9f7bbe4f
commit 1e3b90c971
5 changed files with 70 additions and 5 deletions

View File

@@ -209,8 +209,16 @@ const startServer = async () => {
fastify.register(importRouter, { prefix: '/import' });
fastify.register(trackRouter, { prefix: '/track' });
fastify.setErrorHandler((error, request, reply) => {
request.log.error('request error', { error });
reply.status(500).send('Internal server error');
if (error.statusCode === 429) {
reply.status(429).send({
status: 429,
error: 'Too Many Requests',
message: 'You have exceeded the rate limit for this endpoint.',
});
} else {
request.log.error('request error', { error });
reply.status(500).send('Internal server error');
}
});
fastify.get('/', (_request, reply) => {
reply.send({ name: 'openpanel sdk api' });

View File

@@ -1,10 +1,16 @@
import * as controller from '@/controllers/export.controller';
import { validateExportRequest } from '@/utils/auth';
import { activateRateLimiter } from '@/utils/rate-limiter';
import { Prisma } from '@openpanel/db';
import type { FastifyPluginCallback, FastifyRequest } from 'fastify';
import { Prisma } from '@openpanel/db';
const exportRouter: FastifyPluginCallback = async (fastify, opts, done) => {
await activateRateLimiter({
fastify,
max: 10,
timeWindow: '10 seconds',
});
const eventRouter: FastifyPluginCallback = (fastify, opts, done) => {
fastify.addHook('preHandler', async (req: FastifyRequest, reply) => {
try {
const client = await validateExportRequest(req.headers);
@@ -43,4 +49,4 @@ const eventRouter: FastifyPluginCallback = (fastify, opts, done) => {
done();
};
export default eventRouter;
export default exportRouter;

View File

@@ -0,0 +1,34 @@
import { getRedisCache } from '@openpanel/redis';
import type { FastifyInstance } from 'fastify';
export async function activateRateLimiter({
fastify,
max,
timeWindow,
}: {
fastify: FastifyInstance;
max: number;
timeWindow?: string;
}) {
await fastify.register(import('@fastify/rate-limit'), {
max,
timeWindow: timeWindow || '1 minute',
errorResponseBuilder: (req, reply) => {
return {
statusCode: 429,
error: 'Too Many Requests',
message: 'You have exceeded the rate limit for this endpoint.',
};
},
redis: getRedisCache(),
keyGenerator(req) {
return (req.headers['openpanel-client-id'] ||
req.headers['x-real-ip'] ||
req.headers['x-client-ip'] ||
req.headers['x-forwarded-for']) as string;
},
onExceeded: (req, reply) => {
req.log.warn('Rate limit exceeded');
},
});
}