mirror of
https://github.com/yusufipk/OpenFrame.git
synced 2026-09-11 09:36:08 +00:00
Merge pull request #34 from yusufipk/fix/bigint-safe-success-response
fix(api): serialize BigInt in all API success responses
This commit is contained in:
@@ -2,7 +2,6 @@ import { NextRequest } from 'next/server';
|
||||
import { db } from '@/lib/db';
|
||||
import { auth, checkProjectAccess } from '@/lib/auth';
|
||||
import { validateUrl, validateOptionalUrlOrAppPath } from '@/lib/validation';
|
||||
import { toJsonSafe } from '@/lib/json-serialize';
|
||||
import { rateLimit } from '@/lib/rate-limit';
|
||||
import { notifyProjectOwner } from '@/lib/notifications';
|
||||
import { apiErrors, successResponse, withCacheControl } from '@/lib/api-response';
|
||||
@@ -264,7 +263,7 @@ export async function POST(request: NextRequest, { params }: RouteParams) {
|
||||
}).catch((err) => logError('Notification failed:', err));
|
||||
}
|
||||
|
||||
const response = successResponse(toJsonSafe(version), 201);
|
||||
const response = successResponse(version, 201);
|
||||
return withCacheControl(response, 'private, no-store');
|
||||
} catch (error) {
|
||||
logError('Error creating version:', error);
|
||||
|
||||
@@ -2,7 +2,6 @@ import { NextRequest } from 'next/server';
|
||||
import { db } from '@/lib/db';
|
||||
import { auth, checkProjectAccess } from '@/lib/auth';
|
||||
import { validateUrl, validateOptionalUrlOrAppPath } from '@/lib/validation';
|
||||
import { toJsonSafe } from '@/lib/json-serialize';
|
||||
import { rateLimit } from '@/lib/rate-limit';
|
||||
import { notifyProjectOwner } from '@/lib/notifications';
|
||||
import { apiErrors, successResponse, withCacheControl } from '@/lib/api-response';
|
||||
@@ -269,7 +268,7 @@ export async function POST(request: NextRequest, { params }: RouteParams) {
|
||||
}).catch((err) => logError('Notification failed:', err));
|
||||
}
|
||||
|
||||
const response = successResponse(toJsonSafe(video), 201);
|
||||
const response = successResponse(video, 201);
|
||||
return withCacheControl(response, 'private, no-store');
|
||||
} catch (error) {
|
||||
logError('Error creating video:', error);
|
||||
|
||||
+10
-1
@@ -1,4 +1,5 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { bigIntReplacer } from '@/lib/json-serialize';
|
||||
|
||||
/**
|
||||
* Standardized API error response format
|
||||
@@ -113,6 +114,11 @@ export function errorResponse(
|
||||
* @param status - HTTP status code (default: 200)
|
||||
* @param meta - Pagination or other metadata (optional)
|
||||
*
|
||||
* Serialized with bigIntReplacer rather than NextResponse.json(), because
|
||||
* JSON.stringify throws on BigInt and Prisma returns BigInt for sizeBytes.
|
||||
* Any payload carrying a VideoVersion or VideoAsset row would otherwise 500
|
||||
* after its write had already committed. BigInt values render as strings.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* return successResponse({ projects: [] });
|
||||
@@ -127,7 +133,10 @@ export function successResponse<T>(
|
||||
const body: ApiSuccessResponse<T> = { data };
|
||||
if (meta) body.meta = meta;
|
||||
|
||||
return NextResponse.json(body, { status });
|
||||
return new NextResponse(JSON.stringify(body, bigIntReplacer), {
|
||||
status,
|
||||
headers: { 'content-type': 'application/json' },
|
||||
}) as NextResponse<ApiSuccessResponse<T>>;
|
||||
}
|
||||
|
||||
export function withCacheControl(response: Response, value: string): Response {
|
||||
|
||||
+13
-3
@@ -1,8 +1,18 @@
|
||||
/**
|
||||
* JSON.stringify replacer that renders Prisma BigInt columns (sizeBytes) as
|
||||
* strings. Without it, JSON.stringify throws on any payload carrying one.
|
||||
*/
|
||||
export function bigIntReplacer(_key: string, value: unknown): unknown {
|
||||
return typeof value === 'bigint' ? value.toString() : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts values for JSON responses (e.g. Prisma BigInt fields).
|
||||
*
|
||||
* API routes do not need this — successResponse() serializes BigInt already.
|
||||
* Use it for payloads that bypass that helper, such as data handed from a
|
||||
* server component to a client component.
|
||||
*/
|
||||
export function toJsonSafe<T>(value: T): T {
|
||||
return JSON.parse(
|
||||
JSON.stringify(value, (_key, val) => (typeof val === 'bigint' ? val.toString() : val))
|
||||
) as T;
|
||||
return JSON.parse(JSON.stringify(value, bigIntReplacer)) as T;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user