API-reference

Fejlkoder & HTTP-status

Hvilke HTTP-koder Ressourcify-API'et returnerer, og hvordan fejlobjektet er bygget op.

API'et følger RFC 7807 — Problem Details for HTTP APIs. Alle fejl returneres som JSON med Content-Type: application/problem+json.

Fejlobjekt-format

{
  "type": "about:blank",
  "title": "Validation failed",
  "status": 422,
  "detail": "Request body did not match the expected schema.",
  "errors": [
    { "path": ["startDate"], "message": "Required", "code": "invalid_type" }
  ]
}
FeltTypeNote
typestringDefault "about:blank" — RFC-anbefalet placeholder
titlestringKort, læselig titel — én af nedenstående
statusnumberMatcher HTTP-statuskoden
detailstring?Forklaring til mennesker
instancestring?URI til den fejlende request (sjældent sat)
errorsarray?Kun ved validation-fejl — liste af Zod-issues

HTTP-statuskoder

KodeTitelHvornårHelper
400Bad RequestGenerisk fejl der ikke passer andetstedsProblems.badRequest(detail)
401Unauthorizedauth() returnerede null — ikke logget indProblems.unauthorized(detail)
403ForbiddenLogget ind, men can() returnerede falseProblems.forbidden(detail)
404Not FoundRessource findes ikke, eller findes i anden orgProblems.notFound(detail)
409ConflictUnique constraint (Prisma P2002) — fx duplicate codeProblems.conflict(detail)
422Validation failedZod-skema afviste body eller queryProblems.validation(zodError)
500Internal Server ErrorUventet fejl — logges med logger.errorProblems.internal(detail)

Hvorfor 404 og ikke 403 for cross-org-adgang? Hvis en bruger forsøger at læse en ressource i en anden organisation, returnerer vi 404 for ikke at lække eksistensen af ressourcen. Et 403 ville bekræfte at ressourcen findes — netop hvad vi vil undgå.

Eksempel-svar

401 Unauthorized

{
  "type": "about:blank",
  "title": "Unauthorized",
  "status": 401
}

403 Forbidden

{
  "type": "about:blank",
  "title": "Forbidden",
  "status": 403,
  "detail": "DEPT_ADMIN required for this department"
}

404 Not Found

{
  "type": "about:blank",
  "title": "Not Found",
  "status": 404
}

409 Conflict

{
  "type": "about:blank",
  "title": "Conflict",
  "status": 409,
  "detail": "A project with this code already exists"
}

422 Validation failed

{
  "type": "about:blank",
  "title": "Validation failed",
  "status": 422,
  "detail": "Request body did not match the expected schema.",
  "errors": [
    {
      "path": ["allocationKind"],
      "message": "Invalid enum value. Expected 'HOURS' | 'PERCENT', received 'TIMER'",
      "code": "invalid_enum_value"
    },
    {
      "path": ["value"],
      "message": "Required",
      "code": "invalid_type"
    }
  ]
}

Prisma-fejl der mapper til HTTP-koder

Prisma errorHTTPHelper
P2002 (unique constraint)409Problems.conflict()
P2025 (record not found)404Problems.notFound()
P2003 (FK constraint)400Problems.badRequest()
Alle andre500Problems.internal() + log

Mønster i en route-handler

import { auth } from "@/auth"
import { Problems } from "@/lib/api/problem"
import { can } from "@/lib/authz"
import { Prisma } from "@/app/generated/prisma/client"
import { logger } from "@/lib/logger"
 
export async function POST(req: Request) {
  const session = await auth()
  if (!session) return Problems.unauthorized()
 
  const parsed = AssignmentSchema.safeParse(await req.json())
  if (!parsed.success) return Problems.validation(parsed.error)
 
  if (!can(session, "edit", { type: "assignment", ...parsed.data })) {
    return Problems.forbidden()
  }
 
  try {
    const assignment = await db.assignment.create({ data: parsed.data })
    return NextResponse.json(assignment, { status: 201 })
  } catch (err) {
    if (err instanceof Prisma.PrismaClientKnownRequestError) {
      if (err.code === "P2002") return Problems.conflict("Duplicate")
      if (err.code === "P2025") return Problems.notFound()
    }
    logger.error({ err }, "Failed to create assignment")
    return Problems.internal()
  }
}

Hvad fejl-svar ikke indeholder

  • Stack traces
  • Database-query'er
  • Brugerens session-data
  • Andre brugeres data

Disse logges server-side via logger.error() men sendes aldrig til klienten.

On this page