phase-8g: rate limiting and update readme doc
This commit is contained in:
committed by
saikiranvella
parent
5af9ded35e
commit
d1556f2a67
+22
-1
@@ -1,5 +1,6 @@
|
||||
import Fastify from 'fastify';
|
||||
import Fastify, { type FastifyRequest, type FastifyReply } from 'fastify';
|
||||
import cors from '@fastify/cors';
|
||||
import rateLimit from '@fastify/rate-limit';
|
||||
import { ScreenerController } from './controllers/screener.controller';
|
||||
import { FinanceController } from './controllers/finance.controller';
|
||||
import { CallsController } from './controllers/calls.controller';
|
||||
@@ -31,6 +32,26 @@ export async function buildApp({ logger = true }: BuildAppOptions = {}) {
|
||||
origin: process.env.CLIENT_ORIGIN ?? 'http://localhost:5173',
|
||||
});
|
||||
|
||||
// ── Rate limiting — applied globally, tightest on expensive routes ───────
|
||||
await app.register(rateLimit, {
|
||||
global: false, // opt-in per route via config.rateLimit
|
||||
max: 60,
|
||||
timeWindow: '1 minute',
|
||||
});
|
||||
|
||||
// ── API key auth — only enforced when API_KEY env var is set ─────────────
|
||||
const API_KEY = process.env.API_KEY;
|
||||
if (API_KEY) {
|
||||
app.addHook('onRequest', async (req: FastifyRequest, reply: FastifyReply) => {
|
||||
// Skip auth for health check and OPTIONS preflight
|
||||
if (req.url === '/health' || req.method === 'OPTIONS') return;
|
||||
const header = req.headers['authorization'] ?? '';
|
||||
if (header !== `Bearer ${API_KEY}`) {
|
||||
return reply.code(401).send({ error: 'Unauthorized' });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const yahoo = new YahooFinanceClient();
|
||||
const benchmark = new BenchmarkProvider(yahoo, { logger: noopLogger });
|
||||
const engine = new ScreenerEngine(yahoo, benchmark, { logger: noopLogger });
|
||||
|
||||
@@ -10,7 +10,11 @@ export class AnalyzeController {
|
||||
) {}
|
||||
|
||||
register(app: FastifyInstance): void {
|
||||
app.post('/api/analyze', { schema: analyzeSchema }, this.analyze.bind(this));
|
||||
app.post(
|
||||
'/api/analyze',
|
||||
{ schema: analyzeSchema, config: { rateLimit: { max: 10, timeWindow: '1 minute' } } },
|
||||
this.analyze.bind(this),
|
||||
);
|
||||
}
|
||||
|
||||
private async analyze(req: FastifyRequest, reply: FastifyReply) {
|
||||
|
||||
@@ -8,8 +8,16 @@ export class ScreenerController {
|
||||
constructor(private readonly engine: ScreenerEngine) {}
|
||||
|
||||
register(app: FastifyInstance): void {
|
||||
app.post('/api/screen', { schema: screenSchema }, this.screen.bind(this));
|
||||
app.get('/api/screen/catalysts', this.catalysts.bind(this));
|
||||
app.post(
|
||||
'/api/screen',
|
||||
{ schema: screenSchema, config: { rateLimit: { max: 10, timeWindow: '1 minute' } } },
|
||||
this.screen.bind(this),
|
||||
);
|
||||
app.get(
|
||||
'/api/screen/catalysts',
|
||||
{ config: { rateLimit: { max: 10, timeWindow: '1 minute' } } },
|
||||
this.catalysts.bind(this),
|
||||
);
|
||||
}
|
||||
|
||||
private static serializeAssets(arr: LiveAssetResult[]) {
|
||||
|
||||
Reference in New Issue
Block a user