From a8835f385e69fcb208feb8e0741697430cf84329 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 28 Feb 2025 16:58:57 -0800 Subject: [PATCH] Refactored batch route. --- src/app/api/batch/route.ts | 39 ++++++++++++++++++++++++++++++++++++ src/app/api/send/route.ts | 2 +- src/lib/request.ts | 4 ++-- src/pages/api/batch.ts | 41 -------------------------------------- 4 files changed, 42 insertions(+), 44 deletions(-) create mode 100644 src/app/api/batch/route.ts delete mode 100644 src/pages/api/batch.ts diff --git a/src/app/api/batch/route.ts b/src/app/api/batch/route.ts new file mode 100644 index 00000000..87e04110 --- /dev/null +++ b/src/app/api/batch/route.ts @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import * as send from '@/app/api/send/route'; +import { parseRequest } from '@/lib/request'; +import { json, serverError } from '@/lib/response'; + +const schema = z.array(z.object({}).passthrough()); + +export async function POST(request: Request) { + try { + const { body, error } = await parseRequest(request, schema, { skipAuth: true }); + + if (error) { + return error(); + } + + const errors = []; + + let index = 0; + for (const data of body) { + const newRequest = new Request(request, { body: JSON.stringify(data) }); + const response = await send.POST(newRequest); + + if (!response.ok) { + errors.push({ index, response: await response.json() }); + } + + index++; + } + + return json({ + size: body.length, + processed: body.length - errors.length, + errors: errors.length, + details: errors, + }); + } catch (e) { + return serverError(e); + } +} diff --git a/src/app/api/send/route.ts b/src/app/api/send/route.ts index 933ef78e..80db8f96 100644 --- a/src/app/api/send/route.ts +++ b/src/app/api/send/route.ts @@ -21,7 +21,7 @@ const schema = z.object({ referrer: urlOrPathParam.optional(), screen: z.string().max(11).optional(), title: z.string().optional(), - url: urlOrPathParam, + url: urlOrPathParam.optional(), name: z.string().max(50).optional(), tag: z.string().max(50).optional(), ip: z.string().ip().optional(), diff --git a/src/lib/request.ts b/src/lib/request.ts index 9d32f89b..0c71537a 100644 --- a/src/lib/request.ts +++ b/src/lib/request.ts @@ -1,4 +1,4 @@ -import { ZodObject } from 'zod'; +import { ZodSchema } from 'zod'; import { FILTER_COLUMNS } from '@/lib/constants'; import { badRequest, unauthorized } from '@/lib/response'; import { getAllowedUnits, getMinimumUnit } from '@/lib/date'; @@ -15,7 +15,7 @@ export async function getJsonBody(request: Request) { export async function parseRequest( request: Request, - schema?: ZodObject, + schema?: ZodSchema, options?: { skipAuth: boolean }, ): Promise { const url = new URL(request.url); diff --git a/src/pages/api/batch.ts b/src/pages/api/batch.ts deleted file mode 100644 index 0557d4da..00000000 --- a/src/pages/api/batch.ts +++ /dev/null @@ -1,41 +0,0 @@ -import sendHandler from './send'; - -export default async function handler(req, res) { - if (req.method !== 'POST') { - res.setHeader('Allow', ['POST']); - return res.status(405).end(`Method ${req.method} Not Allowed`); - } - - const events = req.body; - - if (!Array.isArray(events)) { - return res.status(400).json({ error: 'Invalid payload, expected an array.' }); - } - - try { - for (const event of events) { - const mockReq = { - ...req, - body: event, - headers: { ...req.headers, origin: req.headers.origin || 'http://localhost:3000' }, - }; - - const mockRes = { - ...res, - status: (code) => { - res.status(code); - return mockRes; - }, - json: (data) => res.json(data), - setHeader: (key, value) => res.setHeader(key, value), - end: () => {}, - }; - - await sendHandler(mockReq, mockRes); - } - - return res.status(200).json({ success: true, message: `${events.length} events processed.` }); - } catch (error) { - return res.status(500).json({ error: 'Internal Server Error' }); - } -}