mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 06:40:50 +00:00
feat(api): generic Idempotency-Key support for safe POST retries
Introduces `withIdempotency()` in `src/lib/idempotency.ts` — wraps a mutation handler so that a POST/PUT/PATCH/DELETE carrying an `Idempotency-Key` header is replayed from the cached response instead of running twice. Cache row is keyed by `(userId, key, method, path)` with 24h TTL; replays carry `X-Idempotent-Replay: true` so callers can distinguish them. Applied to the three mutation endpoints most exposed to client retries: • POST `/api/measurements` • POST `/api/mood-entries` • POST `/api/medications/[id]/intake` Without the header: zero behaviour change. Existing clients that don't send the header simply skip the cache lookup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
c8387d4f2b
commit
9766cedea4
5 files changed
+338
-6
No files matched your search
@@ -9,6 +9,8 @@ import {
|
||||
listMeasurementsSchema,
|
||||
getUnitForType,
|
||||
} from "@/lib/validations/measurement";
|
||||
import { withIdempotency } from "@/lib/idempotency";
|
||||
import { getSession } from "@/lib/auth/session";
|
||||
import { NextRequest } from "next/server";
|
||||
import type {
|
||||
MeasurementType,
|
||||
@@ -17,6 +19,11 @@ import type {
|
||||
} from "@/generated/prisma/client";
|
||||
import { Prisma } from "@/generated/prisma/client";
|
||||
|
||||
async function resolveUserIdForIdempotency(): Promise<string | null> {
|
||||
const session = await getSession().catch(() => null);
|
||||
return session?.user.id ?? null;
|
||||
}
|
||||
|
||||
export const GET = apiHandler(async (request: NextRequest) => {
|
||||
const { user } = await requireAuth();
|
||||
|
||||
@@ -59,7 +66,11 @@ export const GET = apiHandler(async (request: NextRequest) => {
|
||||
});
|
||||
});
|
||||
|
||||
export const POST = apiHandler(async (request: NextRequest) => {
|
||||
export const POST = apiHandler(
|
||||
withIdempotency<[NextRequest]>(postMeasurement, resolveUserIdForIdempotency),
|
||||
);
|
||||
|
||||
async function postMeasurement(request: NextRequest) {
|
||||
const { user } = await requireAuth();
|
||||
|
||||
const { data: body, error: jsonError } = await safeJson(request);
|
||||
@@ -159,4 +170,4 @@ export const POST = apiHandler(async (request: NextRequest) => {
|
||||
});
|
||||
|
||||
return apiSuccess(measurement, 201);
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user