Course navigationPhase 05
Volume 02 · Phase 05

HTTP, REST & API Engineering

Design HTTP APIs using resources, methods, status codes, idempotency, errors, caching semantics, and versionable contracts.

13lessons + labs
7klesson words
9source references
What you will ship

Phase outcome and project increment

Learning outcome

Design HTTP APIs using resources, methods, status codes, idempotency, errors, caching semantics, and versionable contracts.

Concrete deliverable

A written TaskFlow API contract for tasks with request/response examples and deliberate error semantics.

Figure 5.1 — Where this phase lives in TaskFlow
Client intent
HTTP method + URI
headers/body
server processing
status + response representation
client state transition
Trace the flow left-to-right for implementation and right-to-left for debugging. At every arrow, ask what data crosses the boundary and what proves it is trustworthy.
Instructor mental model

Principles to keep while coding

01

Design APIs around resources, contracts, and HTTP semantics rather than controller method names.

02

Use status codes consistently so clients can distinguish validation, authentication, authorization, and missing resources.

03

Make request and response contracts explicit enough that frontend and backend can evolve safely.

04

Treat idempotency, pagination, errors, and concurrency as API design concerns, not afterthoughts.

Code-along path

Guided phase lab

Do these in order. Each step should end with evidence before the next one starts.

  1. 01

    Write the task resource shape before writing controller code.

  2. 02

    Design collection and item URIs and justify GET/POST/PATCH/DELETE choices.

  3. 03

    Define success and failure status codes for create, read, update, delete, validation, auth, forbidden, and missing-resource cases.

  4. 04

    Use curl or an API client to inspect raw headers and bodies rather than only frontend behavior.

  5. 05

    Repeat safe/idempotent requests and reason about what should or should not change.

  6. 06

    Write an error envelope that the frontend can parse consistently.

TerminalVerification commands
curl -i http://localhost:4000/health

Predict what each command proves before running it. A command is useful only when its output answers a question.

Debugging studio

Failures you should know how to diagnose

Failure drill 1

Using 200 for every outcome

Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.

Failure drill 2

Encoding actions into routes when resource semantics are clearer

Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.

Failure drill 3

Returning database rows as accidental public contracts

Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.

Failure drill 4

Confusing authentication failures with authorization failures

Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.

Watch-order style

Lessons

The source chapters come first. Every phase now ends with a guided build, a debugging workshop, and an independent challenge so reading turns into transferable skill.

01

HTTP Mental Model

FULL_STACK_DEVELOPER_2026_COMPLETE - Phase 05 HTTP Mental Model VOLUME 02 - FRONTEND + BACKEND FOUNDATIONS HTTP Mental Model Client, server, resource, representation and contract HTTP is the

3 min
02

HTTP Request Response Anatomy

FULL_STACK_DEVELOPER_2026_COMPLETE - Phase 05 HTTP Request and Response Anatomy VOLUME 02 - FRONTEND + BACKEND FOUNDATIONS HTTP Request and Response Anatomy Methods, targets, headers, conten

3 min
03

HTTP Methods Status Codes and Idempotency

FULL_STACK_DEVELOPER_2026_COMPLETE - Phase 05 HTTP Methods, Status Codes and Idempotency VOLUME 02 - FRONTEND + BACKEND FOUNDATIONS HTTP Methods, Status Codes and Idempotency Choose protocol

3 min
04

REST Resource and Route Design

FULL_STACK_DEVELOPER_2026_COMPLETE - Phase 05 REST Resource and Route Design VOLUME 02 - FRONTEND + BACKEND FOUNDATIONS REST Resource and Route Design Collections, members, paths, query para

3 min
05

Build the In Memory Todo API

FULL_STACK_DEVELOPER_2026_COMPLETE - Phase 05 Build the In-Memory Todo API VOLUME 02 - FRONTEND + BACKEND FOUNDATIONS Build the In-Memory Todo API Turn HTTP semantics into observable GET, PO

4 min
06

PowerShell API Testing and Contracts

FULL_STACK_DEVELOPER_2026_COMPLETE - Phase 05 PowerShell API Testing and Contracts VOLUME 02 - FRONTEND + BACKEND FOUNDATIONS PowerShell API Testing and Contracts Exercise TaskFlow HTTP dire

2 min
07

HTTP Error Semantics and Debugging

FULL_STACK_DEVELOPER_2026_COMPLETE - Phase 05 HTTP Error Semantics and Debugging VOLUME 02 - FRONTEND + BACKEND FOUNDATIONS HTTP Error Semantics and Debugging Diagnose method, route, represe

3 min
08

API Design Decisions and Anti Patterns

FULL_STACK_DEVELOPER_2026_COMPLETE - Phase 05 API Design Decisions and Anti-Patterns VOLUME 02 - FRONTEND + BACKEND FOUNDATIONS API Design Decisions and Anti-Patterns Professional contract c

3 min
09

Exercises and Phase Exit

FULL_STACK_DEVELOPER_2026_COMPLETE - Phase 05 Exercises and Phase Exit VOLUME 02 - FRONTEND + BACKEND FOUNDATIONS Exercises and Phase Exit Hands-on HTTP labs, debugging drills and the Phase

3 min
LAB

Guided Build Lab

Purpose Design HTTP APIs using resources, methods, status codes, idempotency, errors, caching semantics, and versionable contracts.

3 min
LAB

Debugging Workshop

Goal Learn to diagnose this phase's failures systematically instead of reinstalling packages, changing random configuration, or copying a fix without understanding it.

2 min
LAB

Phase Synthesis & Independent Challenge

Mission Rebuild the capability of Phase 05 without following the exact code line-by-line. The goal is transfer: can you use the ideas when the variable names, UI, or route shape changes?

2 min
LAB

Mastery Capstone Lab

Integrate Phase 05 without following a transcript.

2 min
Practice ladder

Exercises that increase independence

Guided

Write the task resource shape before writing controller code.

Practice

Define success and failure status codes for create, read, update, delete, validation, auth, forbidden, and missing-resource cases.

Debug

reproduce and diagnose — Using 200 for every outcome.

Independent

deliver A written TaskFlow API contract for tasks with request/response examples and deliberate error semantics.

Explain-back

Can design a resource-oriented route set and Can choose meaningful status codes.

Mastery gate

Do not leave the phase only because you reached the bottom

Phase exit criteria

Knowledge check

Scenario and concept quiz

These questions test engineering choices rather than whether you remember a lesson title.

0/0 correct · 0/8 answered
01Which practice best matches Phase 05's engineering goal?
02Which practice best matches Phase 05's engineering goal?
03Which practice best matches Phase 05's engineering goal?
04Which practice best matches Phase 05's engineering goal?
05You are working through the Phase 05 lab. Which next action is the most disciplined step?
06You are working through the Phase 05 lab. Which next action is the most disciplined step?
07You are working through the Phase 05 lab. Which next action is the most disciplined step?
08You are working through the Phase 05 lab. Which next action is the most disciplined step?
Source snapshot

Reference files

Attempt the work first. Use snapshots to compare a checkpoint, not as a substitute for understanding.

reference/TaskFlow_HTTP_API_Snapshot/package.json
{
  "name": "api",
  "private": true,
  "scripts": {
    "build": "nest build",
    "start": "nest start",
    "start:dev": "nest start --watch"
  },
  "dependencies": {
    "@nestjs/common": "12.0.3",
    "@nestjs/core": "12.0.3",
    "@nestjs/platform-fastify": "12.0.3",
    "reflect-metadata": "^0.2.2",
    "rxjs": "^7.8.2"
  },
  "devDependencies": {
    "@nestjs/cli": "12.0.3",
    "@nestjs/schematics": "12.0.3",
    "@nestjs/testing": "12.0.3",
    "typescript": "~6.0.2"
reference/TaskFlow_HTTP_API_Snapshot/src/app.module.ts
import { Module } from '@nestjs/common';
import { HealthModule } from './health/health.module.js';
import { TodosModule } from './todos/todos.module.js';

@Module({
  imports: [HealthModule, TodosModule],
})
export class AppModule {}
reference/TaskFlow_HTTP_API_Snapshot/src/health/health.controller.ts
import { Controller, Get } from '@nestjs/common';
import { HealthService } from './health.service.js';

@Controller('health')
export class HealthController {
  constructor(private readonly healthService: HealthService) {}

  @Get()
  getHealth() {
    return this.healthService.getStatus();
  }
}
reference/TaskFlow_HTTP_API_Snapshot/src/health/health.module.ts
import { Module } from '@nestjs/common';
import { HealthController } from './health.controller.js';
import { HealthService } from './health.service.js';

@Module({
  controllers: [HealthController],
  providers: [HealthService],
})
export class HealthModule {}
reference/TaskFlow_HTTP_API_Snapshot/src/health/health.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class HealthService {
  getStatus() {
    return {
      status: 'ok',
      service: 'taskflow-api',
    };
  }
}
reference/TaskFlow_HTTP_API_Snapshot/src/main.ts
import { NestFactory } from '@nestjs/core';
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
import { AppModule } from './app.module.js';

async function bootstrap() {
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter(),
  );

  app.enableShutdownHooks();
  const port = Number(process.env.PORT ?? 4000);
  await app.listen(port, '127.0.0.1');
}

void bootstrap();
reference/TaskFlow_HTTP_API_Snapshot/src/todos/todos.controller.ts
import {
  BadRequestException,
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  Param,
  Patch,
  Post,
} from '@nestjs/common';
import { TodosService } from './todos.service.js';

@Controller('todos')
export class TodosController {
  constructor(private readonly todosService: TodosService) {}

  @Get()
  findAll() {
    return this.todosService.findAll();
reference/TaskFlow_HTTP_API_Snapshot/src/todos/todos.module.ts
import { Module } from '@nestjs/common';
import { TodosController } from './todos.controller.js';
import { TodosService } from './todos.service.js';

@Module({
  controllers: [TodosController],
  providers: [TodosService],
})
export class TodosModule {}
reference/TaskFlow_HTTP_API_Snapshot/src/todos/todos.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';

interface Todo {
  id: number;
  title: string;
  completed: boolean;
}

@Injectable()
export class TodosService {
  private nextId = 3;
  private readonly todos: Todo[] = [
    { id: 1, title: 'Learn HTTP', completed: false },
    { id: 2, title: 'Build the API contract', completed: false },
  ];

  findAll() {
    return this.todos;
  }