Welcome: From “It Works” to “It Feels Professional”

Welcome to the final lesson of this course.
So far, you’ve built a fully functional Task Manager API:

  • A clear Task model and in-memory store
  • A service layer handling all task CRUD
  • Validation to keep data safe
  • Middleware with API-key protection and logging
  • A UI panel to exercise all endpoints

In this last lesson, you’ll polish the API surface itself so it feels consistent and predictable to any client:

  • Introduce response helpers that standardize your JSON shape
  • Refactor your /api/tasks and /api/tasks/[id] routes to use those helpers
  • Add a filter endpoint and a small filtered-tasks page that follow the same response contract

You’ll still be using Codex, but now with a focus on refactoring and fine-grained behavior, rather than raw scaffolding.

What We’re Building and Why It Matters

Right now, your routes return JSON directly via NextResponse.json, and different handlers may shape responses slightly differently. That works, but it’s not ideal:

  • Some responses might be { error: '...' }, others raw arrays, others objects with different keys.
  • Your frontend has to remember multiple formats.
  • Adding metadata (like timestamps) requires repeating logic in every route.

This lesson introduces a single, predictable contract.

Success responses look like:

  • A data field with the payload
  • A meta field with a timestamp

Error responses look like:

  • An error field with a clear message
  • A meta field with a timestamp

Once this contract is in place and wired into all handlers, every client (your own UI, tests, or external consumers) can rely on the same structure—across collection routes, item routes, and the new filter endpoint.

How We’ll Use Codex in This Lesson

You’ll direct Codex through three main tasks:

  • Implement response helpers in src/lib/responses.ts.
  • Refactor existing routes (/api/tasks and /api/tasks/[id]) to use those helpers and map service errors to specific HTTP status codes.
  • Finish and polish the filter endpoint + UI so they follow the same response shape and behavior patterns.

Your prompts should:

  • Explicitly list all files Codex may change (often 1 or 2 files per prompt).
  • Describe the response shapes and status code rules clearly.
  • Emphasize “do not modify any other files”.
  • Ask Codex to show the full updated content for each touched file.

These examples capture the consistent “face” of your API.

Step 1: Standardizing JSON with Response Helpers

First, you’ll define reusable helpers in src/lib/responses.ts. The starter file already sketches the idea:

You’ll guide Codex to:

  • Keep the basic structure.
  • Replace the 'TODO' placeholder with the actual message argument.
  • Ensure both helpers always return an object with { data?, error?, meta: { timestamp } }.

After Codex’s implementation, the helpers should conceptually look like:

From here on, routes don’t call NextResponse.json directly—they call these helpers.

A focused Codex prompt might look like:

Codex, modify only .

Step 2: Refactoring /api/tasks and /api/tasks/[id] to Use Helpers

Next, you’ll refactor the collection and item routes to use your new helpers consistently.

/api/tasks Collection Route

The starter version of src/app/api/tasks/route.ts is already partway there (shown above).

You’ll ask Codex to:

  • Replace the placeholder createSuccessResponse([], 200) in GET with getAllTasks():

    • const tasks = getAllTasks();
    • return createSuccessResponse(tasks, 200);
  • Preserve the inline validation in POST, but make sure all outcomes use the helpers:

    • Validation errors → createErrorResponse(errors.join(' '), 400)
    • Successful creation → createSuccessResponse(newTask, 201)

The logic doesn’t change; only the response formatting does.

A prompt you might send:

Codex, modify only src/app/api/tasks/route.ts.

  • In GET, call and return the result with .
/api/tasks/[id] Item Route

The item-level route already knows about the helpers and service layer (as shown above).

Your refactor will focus on how errors are mapped:

  • If updateTaskById returns { error: 'Task not found' }404
  • If it returns { error: '...' } for validation or payload issues → 400
  • If it returns { task }200 with createSuccessResponse(task)

For example, Codex should turn the PUT handler into something like:

PATCH follows the same rules but calls updateTaskById(id, body, true).
DELETE remains the special case: 204 with no JSON body on success, and createErrorResponse('Task not found', 404) when nothing was deleted.

Step 3: Finishing the Filter Endpoint and Its UI with Consistent Responses

The final piece is your filter-by-status feature, which ties together everything you’ve learned: service layer, helpers, validation, and UI.

/api/tasks/filter Route

The starter API route already captures the desired behavior (shown above).

You’ll use Codex to ensure:

  • The completed query param is required.
  • Only 'true' or 'false' are allowed values.
  • Invalid or missing params → 400 with createErrorResponse.
  • Valid params → boolean conversion → filterTaskByStatuscreateSuccessResponse(tasks).

Now this endpoint matches the same response contract as /api/tasks and /api/tasks/[id].

A concise prompt:

Codex, modify only src/app/api/tasks/filter/route.ts.

Implement the GET handler so that it:

  • Reads the completed query parameter.
  • If it is missing, returns createErrorResponse("'completed' query parameter is required", 400).
  • If it is not 'true' or 'false', returns .
Filtered Tasks Page

The UI page completes the story by consuming the filter endpoint.

You’ll ask Codex to:

  • Validate completedParam on the client (if it’s not 'true' or 'false', set an error).
  • Call /api/tasks/filter?completed=... when valid.
  • Remember that responses now come in { data, meta } (and possibly { error, meta }) form, so the UI must read data.

Conceptually, the useEffect implementation should look like:

This page becomes a neat little “view” on top of your consistent backend.

A good Codex prompt for this page:

Codex, modify only src/app/tasks/filter/page.tsx.

In the useEffect, validate completedParam so that if it is not or , and clear the array. When it is valid, call and parse the JSON response.

Summary: What You’ve Achieved in This Course

In this final lesson, you:

  • Created response helpers that standardize JSON responses with { data/error, meta }.
  • Refactored /api/tasks and /api/tasks/[id] to use those helpers and map service errors to appropriate HTTP status codes.
  • Finished the filter endpoint and UI, making sure they follow the same response contract and validation patterns.

Across the entire Vibe Coding the Backend: Task Manager API course, you’ve:

  • Learned to design a domain model and service layer.
  • Used Codex to implement logic safely, one file at a time.
  • Added validation, security, logging, and now consistent responses.
  • Built a UI panel and a filtered view to fully exercise your API.

You now have a small but realistic backend that looks and behaves like something you’d be proud to ship—and you’ve practiced guiding Codex as a real engineering partner, not a magic code generator.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal