Spring Boot Request and Response

Every interaction between a client and your Spring Boot API follows a clear structure. The client sends a request with data. Your app processes it and sends back a response. Understanding the shape of both is essential to building reliable APIs.

Anatomy of an HTTP Request

POST /api/users HTTP/1.1
Host: localhost:8080
Content-Type: application/json         ← Header: what format is the body?
Authorization: Bearer eyJhbGc...       ← Header: authentication token

{                                      ← Body: the actual data
  "name": "Alice",
  "email": "alice@example.com",
  "age": 28
}

Anatomy of an HTTP Response

HTTP/1.1 201 Created                   ← Status line
Content-Type: application/json         ← Header: what format is the body?
Location: /api/users/42                ← Header: where is the new resource?

{                                      ← Body: the response data
  "id": 42,
  "name": "Alice",
  "email": "alice@example.com"
}

Reading the Request Body with @RequestBody

Jackson (included with spring-boot-starter-web) converts the incoming JSON into a Java object automatically:

// Java class (DTO)
public class CreateUserRequest {
    private String name;
    private String email;
    private int age;
    // Getters and setters
}

// Controller
@PostMapping("/users")
public ResponseEntity<UserResponse> createUser(
    @RequestBody CreateUserRequest request   ← JSON body → Java object
) {
    UserResponse saved = userService.create(request);
    return ResponseEntity.status(201).body(saved);
}

DTO Pattern — Separate Request and Response Shapes

A DTO (Data Transfer Object) defines exactly what fields go in or out. Never expose your database entity directly as the API response — it leaks internal structure and sensitive fields.

                     API Boundary
Client               │               Your App
─────────────────────┼───────────────────────────────────────
                     │
  JSON Request  ────▶│──▶  CreateUserRequest DTO
                     │           │
                     │           ▼
                     │     UserService  ───▶  User Entity  ───▶  DB
                     │           │
                     │           ▼
  JSON Response ◀────│──  UserResponse DTO
                     │

CreateUserRequest (what the client sends)

{
  "name": "Alice",
  "email": "alice@example.com",
  "password": "secret123"
}

UserResponse (what the API returns — no password)

{
  "id": 42,
  "name": "Alice",
  "email": "alice@example.com",
  "createdAt": "2024-05-01T10:00:00"
}

Building Responses with ResponseEntity

// 200 OK with body
return ResponseEntity.ok(user);

// 201 Created with body and location header
return ResponseEntity
    .created(URI.create("/api/users/" + user.getId()))
    .body(user);

// 204 No Content (nothing to return)
return ResponseEntity.noContent().build();

// 404 Not Found
return ResponseEntity.notFound().build();

// 400 Bad Request with custom message
return ResponseEntity.badRequest().body("Email already exists");

Customizing JSON Output

Jackson annotations control how Java objects serialize to JSON:

public class UserResponse {

    private Long id;

    @JsonProperty("full_name")        ← JSON key is "full_name", not "name"
    private String name;

    @JsonIgnore                        ← This field is excluded from JSON
    private String password;

    @JsonFormat(pattern = "yyyy-MM-dd")  ← Format dates
    private LocalDate birthDate;
}

Setting Response Headers

@GetMapping("/report")
public ResponseEntity<byte[]> downloadReport() {
    byte[] pdf = reportService.generate();

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_PDF);
    headers.setContentDispositionFormData("attachment", "report.pdf");

    return ResponseEntity.ok().headers(headers).body(pdf);
}

Summary

  • HTTP requests carry method, URL, headers, and an optional body
  • @RequestBody converts the JSON request body into a Java object
  • Use DTOs to control exactly what data enters and exits the API
  • Never expose entity classes directly — use separate request and response DTOs
  • ResponseEntity gives full control over the HTTP status code, headers, and body

Leave a Comment

Your email address will not be published. Required fields are marked *