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
@RequestBodyconverts 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
ResponseEntitygives full control over the HTTP status code, headers, and body
