CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl-labs/nextjs-api-patterns

Next.js App Router API patterns — Route Handlers, Server Actions, middleware, validation, caching, error handling

92

1.58x
Quality

90%

Does it follow best practices?

Impact

95%

1.58x

Average score across 5 eval scenarios

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

criteria.jsonevals/scenario-4/

{
  "context": "Tests whether the agent proactively applies Next.js App Router best practices when building a CRUD API. The task does not mention validation, error handling, caching, or params awaiting -- the agent should add these from knowledge of the tile patterns.",
  "type": "weighted_checklist",
  "checklist": [
    {
      "name": "Params awaited in dynamic routes",
      "description": "Dynamic route handlers ([id]/route.ts) await the params object before accessing id: 'const { id } = await params' with the type { params: Promise<{ id: string }> }. Not accessing params.id directly.",
      "max_score": 15
    },
    {
      "name": "Zod or schema validation on input",
      "description": "POST and PUT handlers validate the request body using zod (or equivalent schema library) with safeParse -- checking name, price, and category constraints rather than manual if-checks",
      "max_score": 14
    },
    {
      "name": "Structured error responses",
      "description": "All error responses use a consistent shape like { error: { code, message } } with appropriate HTTP status codes (400 for validation, 404 for not found, 409 for duplicate name) -- not raw strings or inconsistent formats",
      "max_score": 13
    },
    {
      "name": "request.json() wrapped in try/catch",
      "description": "POST and PUT handlers wrap request.json() in try/catch to handle malformed JSON, returning a 400 error",
      "max_score": 10
    },
    {
      "name": "NextResponse.json used correctly",
      "description": "Handlers return NextResponse.json() with explicit status codes -- 201 for creation, 204 for deletion, 404 for not found -- not Express-style res.status().json()",
      "max_score": 10
    },
    {
      "name": "GET caching control",
      "description": "GET handlers either export dynamic = 'force-dynamic' or use request-dependent APIs to prevent stale cached responses in production, OR the menu page uses fetch with explicit revalidation options",
      "max_score": 10
    },
    {
      "name": "No internal error leaks",
      "description": "Unexpected errors return a generic message (e.g. 'An unexpected error occurred') with 500 status -- no stack traces or internal details in responses",
      "max_score": 8
    },
    {
      "name": "Error boundary for menu page",
      "description": "An error.tsx file with 'use client' directive exists for the menu route segment, providing a user-facing error boundary",
      "max_score": 8
    },
    {
      "name": "CRUD endpoints functional",
      "description": "All five CRUD operations are implemented and return appropriate data shapes with correct status codes",
      "max_score": 12
    }
  ]
}

evals

tile.json