Loading published curriculum…

11 · REST APIs / LESSON 48 OF 102

Controllers and DTOs

Define the HTTP boundary without exposing database internals.

Before this lesson: Configuration and profiles

Understand the topic

@RestController serializes returned objects to the response body. @RequestMapping defines a shared path. @RequestBody converts JSON to a Java object. Records make small DTOs; entities remain separate.

This first endpoint normalizes input without storing it, so it returns 200 rather than falsely claiming durable creation. The persistence section adds a create endpoint with 201 and Location.

EXAMPLE · JAVA

src/main/java/com/example/tasks/TaskController.java

package com.example.tasks;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/tasks")
public class TaskController {
    private final TitleService titles;
    public TaskController(TitleService titles) { this.titles = titles; }
    public record CreateTask(String title) {}
    public record Preview(String title, boolean done) {}
    @PostMapping("/preview")
    public Preview preview(@RequestBody CreateTask input) {
        return new Preview(titles.normalize(input.title()), false);
    }
}

What to expect

POST /api/tasks/preview with {"title":" Java "} returns {"title":"Java","done":false}.

YOUR TURN

Put it into practice

  1. 01Call with curl or an API client.
  2. 02Add a GET ping endpoint.
  3. 03Explain DTO versus entity.

Pass a quiz or complete a lab to check today’s streak. Each lesson counts once per day, including when you review it later.

UNDER THE HOOD

Build the mental model

A controller translates HTTP into an application operation and translates its result back into a public representation.

  1. 01DTOs constrain what clients can send and receive. Binding a request directly into an entity can allow unintended field changes.
  2. 02Constructor injection keeps the controller thin. Put business operations in a service so non-HTTP callers can reuse them.
  3. 03A create operation should return the saved ID. Build Location from that ID rather than guessing the next sequence value.

A mistake worth avoiding

Do not put mutable lists of tasks on a singleton controller for production storage.

DEBUGGING ROOM

Something broke. Where do you look?

The response accidentally exposes a passwordHash field.

Before revealing the diagnosis, write down your first investigation step.

CHECK YOUR UNDERSTANDING

Why use a response DTO?

Choose one answer

BUILD IT YOURSELF

Implement create and read contracts

  1. 1.Add POST /api/tasks backed by TaskService when persistence is available.
  2. 2.Return a record with id, title, and done.
  3. 3.Return 201 with a Location header pointing at GET-one.

Acceptance checklist

Lab completion is your self-report. Knowledge checks do not certify project quality.

RETRIEVE IT FROM MEMORY

What should remain outside an HTTP controller?

Revisit this lesson in three days after a successful check or lab.

Ready for the next step?

Trace JSON → DTO → service → response.

Reading is separate from passing a knowledge check or completing a lab.

Go deeper · official references