Skip to main content

Week 4 Day 2 — Request Mapping Deep Dive

Goal

Today I want to understand request mapping deeply.

Main questions:

  1. What is @RequestMapping?
  2. What are @GetMapping, @PostMapping, @PutMapping, @PatchMapping, and @DeleteMapping?
  3. How do class-level and method-level mappings combine?
  4. What is @PathVariable?
  5. What is @RequestParam?
  6. What is @RequestHeader?
  7. What are params and headers mapping conditions?
  8. What are consumes and produces?
  9. What is content negotiation?
  10. What are common exam traps?

1. Quick Review from Week 4 Day 1

In Day 1, I learned:

  • Spring MVC maps HTTP requests to Java controller methods.
  • DispatcherServlet is the front controller.
  • HandlerMapping finds the correct handler.
  • HandlerAdapter invokes the handler.
  • @RestController means @Controller plus @ResponseBody.
  • @RequestBody reads the HTTP body.
  • @PathVariable reads path values.
  • @RequestParam reads query parameters.
  • HttpMessageConverter converts HTTP bodies to Java objects and Java objects to HTTP bodies.

Memory sentence:

Request -> DispatcherServlet -> HandlerMapping -> Controller -> Response

Today I go deeper into how Spring chooses the correct controller method.


2. What Is @RequestMapping?

@RequestMapping maps web requests to controller classes or methods.

Simple definition:

@RequestMapping tells Spring MVC which HTTP request should be handled by which controller method.

Example:

@RestController
@RequestMapping("/api/tasks")
public class TaskController {

@RequestMapping("/hello")
public String hello() {
return "Hello";
}
}

This handles:

GET /api/tasks/hello
POST /api/tasks/hello
PUT /api/tasks/hello

Why?

Because no HTTP method was specified.

Important:

If no HTTP method is specified, @RequestMapping can match multiple HTTP methods.


3. Better: Specify the HTTP Method

Instead of this:

@RequestMapping("/api/tasks")
public List<TaskDto> list() {
return taskService.findAll();
}

Better:

@GetMapping("/api/tasks")
public List<TaskDto> list() {
return taskService.findAll();
}

Why?

Because the method clearly handles:

GET /api/tasks

not every possible HTTP method.

Memory sentence:

Prefer specific mapping annotations like @GetMapping and @PostMapping in REST controllers.


4. @RequestMapping Can Match Many Conditions

A request mapping can match by:

path
HTTP method
query parameters
headers
consumes content type
produces content type

Example:

@RequestMapping(
path = "/api/tasks",
method = RequestMethod.POST,
consumes = "application/json",
produces = "application/json"
)
public TaskDto create(@RequestBody CreateTaskRequest request) {
return taskService.create(request);
}

This means:

Path must be /api/tasks.
HTTP method must be POST.
Request body must be JSON.
Response will be JSON.

5. Shortcut Mapping Annotations

Spring provides shortcut annotations:

@GetMapping
@PostMapping
@PutMapping
@PatchMapping
@DeleteMapping

They are shortcuts for @RequestMapping(method = ...).

Example:

@GetMapping("/api/tasks")

is a shortcut for:

@RequestMapping(
path = "/api/tasks",
method = RequestMethod.GET
)

Memory sentence:

Shortcut mappings are clearer for REST APIs.


6. HTTP Method Meaning in REST

HTTP MethodCommon REST Meaning
GETread data
POSTcreate a new resource or execute command
PUTreplace a resource
PATCHpartially update a resource
DELETEdelete a resource

Example:

GET /api/tasks -> list tasks
GET /api/tasks/123 -> get one task
POST /api/tasks -> create task
PUT /api/tasks/123 -> replace task
PATCH /api/tasks/123 -> update part of task
DELETE /api/tasks/123 -> delete task

7. Full REST Mapping Example

@RestController
@RequestMapping("/api/tasks")
public class TaskController {

@GetMapping
public List<TaskDto> list() {
return taskService.findAll();
}

@GetMapping("/{id}")
public TaskDto get(@PathVariable Long id) {
return taskService.findById(id);
}

@PostMapping
public ResponseEntity<TaskDto> create(@RequestBody CreateTaskRequest request) {
TaskDto created = taskService.create(request);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}

@PutMapping("/{id}")
public TaskDto replace(
@PathVariable Long id,
@RequestBody ReplaceTaskRequest request
) {
return taskService.replace(id, request);
}

@PatchMapping("/{id}")
public TaskDto update(
@PathVariable Long id,
@RequestBody UpdateTaskRequest request
) {
return taskService.update(id, request);
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
taskService.delete(id);
return ResponseEntity.noContent().build();
}
}

Mappings:

GET /api/tasks -> list()
GET /api/tasks/123 -> get(123)
POST /api/tasks -> create(request)
PUT /api/tasks/123 -> replace(123, request)
PATCH /api/tasks/123 -> update(123, request)
DELETE /api/tasks/123 -> delete(123)

8. Class-Level and Method-Level Mapping

Class-level mapping:

@RequestMapping("/api/tasks")

Method-level mapping:

@GetMapping("/{id}")

Combined:

GET /api/tasks/{id}

Example:

@RestController
@RequestMapping("/api/clients")
public class ClientController {

@GetMapping("/{id}")
public ClientDto getClient(@PathVariable Long id) {
return clientService.findById(id);
}
}

This handles:

GET /api/clients/10

Memory sentence:

Class-level path plus method-level path creates the final endpoint path.


9. Empty Method Mapping

Example:

@RestController
@RequestMapping("/api/tasks")
public class TaskController {

@GetMapping
public List<TaskDto> list() {
return taskService.findAll();
}
}

@GetMapping has no path.

It uses the class-level path:

GET /api/tasks

This is common and clean.


10. Avoid Repeating Full Paths

Less clean:

@RestController
public class TaskController {

@GetMapping("/api/tasks")
public List<TaskDto> list() {
return taskService.findAll();
}

@GetMapping("/api/tasks/{id}")
public TaskDto get(@PathVariable Long id) {
return taskService.findById(id);
}
}

Cleaner:

@RestController
@RequestMapping("/api/tasks")
public class TaskController {

@GetMapping
public List<TaskDto> list() {
return taskService.findAll();
}

@GetMapping("/{id}")
public TaskDto get(@PathVariable Long id) {
return taskService.findById(id);
}
}

Memory sentence:

Put the common base path on the controller class.


11. @PathVariable

@PathVariable reads a value from the URL path.

Request:

GET /api/tasks/123

Controller:

@GetMapping("/api/tasks/{id}")
public TaskDto getTask(@PathVariable Long id) {
return taskService.findById(id);
}

Spring binds:

123 -> id

12. Multiple Path Variables

Request:

GET /api/clients/10/tasks/99

Controller:

@GetMapping("/api/clients/{clientId}/tasks/{taskId}")
public TaskDto getClientTask(
@PathVariable Long clientId,
@PathVariable Long taskId
) {
return taskService.findClientTask(clientId, taskId);
}

Spring binds:

clientId = 10
taskId = 99

13. Path Variable Name Differs from Parameter Name

Path:

@GetMapping("/api/tasks/{taskId}")

Parameter:

public TaskDto getTask(@PathVariable("taskId") Long id) {
return taskService.findById(id);
}

Spring binds:

URL variable taskId -> Java parameter id

Use this when Java parameter name differs from path variable name.


14. Type Conversion for Path Variables

Path variables are text in the URL.

Example:

GET /api/tasks/123

Spring receives:

"123"

Controller expects:

@PathVariable Long id

Spring converts:

"123" -> Long 123

If conversion fails:

GET /api/tasks/abc

Spring cannot convert:

"abc" -> Long

Usually response:

400 Bad Request

Memory sentence:

Path variables are strings first, then Spring converts them to the target type.


15. @RequestParam

@RequestParam reads query parameters.

Request:

GET /api/tasks?page=0&size=20

Controller:

@GetMapping("/api/tasks")
public List<TaskDto> list(
@RequestParam int page,
@RequestParam int size
) {
return taskService.findPage(page, size);
}

Spring binds:

page=0 -> page
size=20 -> size

16. Required Request Parameters

By default, @RequestParam is required.

Example:

@GetMapping("/api/tasks")
public List<TaskDto> list(@RequestParam String status) {
return taskService.findByStatus(status);
}

Request:

GET /api/tasks

No status parameter.

Usually response:

400 Bad Request

Because required query parameter is missing.


17. Optional Request Parameters

Option 1: required = false

@GetMapping("/api/tasks")
public List<TaskDto> list(
@RequestParam(required = false) String status
) {
return taskService.findByStatus(status);
}

If missing:

status = null

Option 2: Optional

@GetMapping("/api/tasks")
public List<TaskDto> list(
@RequestParam Optional<String> status
) {
return taskService.findByStatus(status);
}

Option 3: default value

@GetMapping("/api/tasks")
public List<TaskDto> list(
@RequestParam(defaultValue = "OPEN") String status
) {
return taskService.findByStatus(status);
}

If missing:

status = OPEN

Memory sentence:

@RequestParam is required by default unless made optional or given a default value.


18. Request Parameter Name Differs from Java Parameter

Request:

GET /api/tasks?task_status=OPEN

Controller:

@GetMapping("/api/tasks")
public List<TaskDto> list(
@RequestParam("task_status") String status
) {
return taskService.findByStatus(status);
}

Spring binds:

task_status -> status

19. RequestParam Type Conversion

Request:

GET /api/tasks?page=0&size=20&archived=false

Controller:

@GetMapping("/api/tasks")
public List<TaskDto> list(
@RequestParam int page,
@RequestParam int size,
@RequestParam boolean archived
) {
return taskService.find(page, size, archived);
}

Spring converts:

"0" -> int 0
"20" -> int 20
"false" -> boolean false

If conversion fails:

GET /api/tasks?page=abc

Usually response:

400 Bad Request

20. Multiple Values for Same Query Parameter

Request:

GET /api/tasks?status=OPEN&status=DONE

Controller:

@GetMapping("/api/tasks")
public List<TaskDto> list(
@RequestParam List<String> status
) {
return taskService.findByStatuses(status);
}

Spring binds:

status = ["OPEN", "DONE"]

This is useful for filters.


21. @RequestHeader

@RequestHeader reads HTTP headers.

Request:

GET /api/tasks
X-Tenant-Id: tenant-123

Controller:

@GetMapping("/api/tasks")
public List<TaskDto> list(
@RequestHeader("X-Tenant-Id") String tenantId
) {
return taskService.findForTenant(tenantId);
}

Spring binds:

X-Tenant-Id -> tenantId

22. Optional Request Header

@GetMapping("/api/tasks")
public List<TaskDto> list(
@RequestHeader(value = "X-Request-Id", required = false) String requestId
) {
return taskService.findAll(requestId);
}

If header is missing:

requestId = null

With default value:

@GetMapping("/api/tasks")
public List<TaskDto> list(
@RequestHeader(value = "X-Client-Version", defaultValue = "unknown") String clientVersion
) {
return taskService.findAll(clientVersion);
}

23. @RequestBody

@RequestBody reads the HTTP request body.

Request:

POST /api/tasks
Content-Type: application/json

{
"title": "Learn Spring MVC"
}

Controller:

@PostMapping("/api/tasks")
public TaskDto create(@RequestBody CreateTaskRequest request) {
return taskService.create(request);
}

Spring uses an HttpMessageConverter to convert JSON into:

CreateTaskRequest

DTO:

public record CreateTaskRequest(String title) {
}

Memory sentence:

@RequestBody means body to Java object.


24. @RequestBody Is Usually for POST, PUT, PATCH

Common use:

POST -> create body
PUT -> replace body
PATCH -> partial update body

Less common:

GET with body

In REST APIs, avoid GET request bodies.

Use query parameters for filtering and pagination.

Example:

GET /api/tasks?status=OPEN&page=0&size=20

not:

GET /api/tasks

{
"status": "OPEN"
}

Memory sentence:

Use query parameters for GET filters. Use request body for create/update commands.


25. One @RequestBody Per Method

Usually one controller method has one request body.

Bad:

@PostMapping("/api/tasks")
public TaskDto create(
@RequestBody CreateTaskRequest request,
@RequestBody Metadata metadata
) {
return taskService.create(request, metadata);
}

Why bad?

The HTTP request has one body.
Spring cannot normally read two separate request bodies into two objects.

Better:

public record CreateTaskCommand(
String title,
Metadata metadata
) {
}

Controller:

@PostMapping("/api/tasks")
public TaskDto create(@RequestBody CreateTaskCommand command) {
return taskService.create(command);
}

Memory sentence:

One HTTP request has one body, so use one @RequestBody object.


26. Mapping with Query Parameter Conditions: params

params in mapping means:

This method should match only if specific query parameters are present or have certain values.

Example:

@GetMapping(value = "/api/tasks", params = "status")
public List<TaskDto> listByStatus(@RequestParam String status) {
return taskService.findByStatus(status);
}

This matches:

GET /api/tasks?status=OPEN

But not:

GET /api/tasks

27. Mapping by Parameter Value

@GetMapping(value = "/api/tasks", params = "status=OPEN")
public List<TaskDto> openTasks() {
return taskService.findOpenTasks();
}

This matches:

GET /api/tasks?status=OPEN

But not:

GET /api/tasks?status=DONE

28. Mapping by Missing Parameter

@GetMapping(value = "/api/tasks", params = "!status")
public List<TaskDto> listAll() {
return taskService.findAll();
}

This matches:

GET /api/tasks

But not:

GET /api/tasks?status=OPEN

Memory sentence:

params is a mapping condition. @RequestParam reads the value.


29. params vs @RequestParam

This is an important exam trap.

params

Used in mapping selection.

@GetMapping(value = "/api/tasks", params = "status")

Meaning:

This method matches only if the request has status parameter.

@RequestParam

Used to bind the value to a method parameter.

public List<TaskDto> list(@RequestParam String status)

Meaning:

Read status value into Java parameter.

Memory sentence:

params chooses the method. @RequestParam reads the value.


30. Mapping with Header Conditions: headers

headers in mapping means:

This method should match only if specific headers are present or have certain values.

Example:

@GetMapping(value = "/api/tasks", headers = "X-API-Version=1")
public List<TaskDto> listV1() {
return taskService.findAllV1();
}

This matches:

GET /api/tasks
X-API-Version: 1

But not:

GET /api/tasks
X-API-Version: 2

31. Header Present Condition

@GetMapping(value = "/api/tasks", headers = "X-Tenant-Id")
public List<TaskDto> listForTenant(
@RequestHeader("X-Tenant-Id") String tenantId
) {
return taskService.findForTenant(tenantId);
}

This method matches only if the request has:

X-Tenant-Id

header.

Memory sentence:

headers chooses the method. @RequestHeader reads the header value.


32. headers vs @RequestHeader

headers

Mapping condition:

@GetMapping(value = "/api/tasks", headers = "X-API-Version=2")

@RequestHeader

Value binding:

public List<TaskDto> list(@RequestHeader("X-API-Version") String version)

Memory sentence:

headers controls matching. @RequestHeader reads data.


33. consumes

consumes means:

This method accepts requests with a specific Content-Type.

Example:

@PostMapping(
value = "/api/tasks",
consumes = "application/json"
)
public TaskDto create(@RequestBody CreateTaskRequest request) {
return taskService.create(request);
}

This matches:

POST /api/tasks
Content-Type: application/json

But not:

POST /api/tasks
Content-Type: text/plain

Memory sentence:

consumes checks the request body content type.


34. Content-Type Header

consumes uses the request Content-Type.

Example:

Content-Type: application/json

means:

The request body is JSON.

If controller says:

consumes = "application/json"

then the request must send compatible JSON content type.


35. Wrong Content-Type

Controller:

@PostMapping(
value = "/api/tasks",
consumes = "application/json"
)
public TaskDto create(@RequestBody CreateTaskRequest request) {
return taskService.create(request);
}

Request:

POST /api/tasks
Content-Type: text/plain

hello

Usually response:

415 Unsupported Media Type

Because the server does not support that request body media type for this endpoint.


36. produces

produces means:

This method can produce a specific response media type.

Example:

@GetMapping(
value = "/api/tasks",
produces = "application/json"
)
public List<TaskDto> list() {
return taskService.findAll();
}

This means the method produces JSON.

Client request:

GET /api/tasks
Accept: application/json

Spring can return JSON.

Memory sentence:

produces describes the response content type.


37. Accept Header

The client can send:

Accept: application/json

Meaning:

I want JSON response.

The server method can declare:

produces = "application/json"

Meaning:

I can produce JSON.

If client asks for something the server cannot produce, response may be:

406 Not Acceptable

38. consumes vs produces

Mapping AttributeLooks atMeaning
consumesrequest Content-Typewhat the endpoint accepts
producesrequest Accept header / response typewhat the endpoint returns

Memory sentence:

consumes = request body format.
produces = response body format.

39. JSON Controller Example with Consumes and Produces

@RestController
@RequestMapping("/api/tasks")
public class TaskController {

@PostMapping(
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<TaskDto> create(
@RequestBody CreateTaskRequest request
) {
TaskDto created = taskService.create(request);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}
}

This endpoint:

accepts JSON request body
returns JSON response body

40. MediaType Constants

Instead of hardcoding:

"application/json"

Use:

MediaType.APPLICATION_JSON_VALUE

Example:

@PostMapping(
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)

This avoids typos.


41. Content Negotiation

Content negotiation means:

Spring chooses the response format based on what the client asks for and what the server can produce.

Client:

Accept: application/json

Controller:

@GetMapping(value = "/api/tasks", produces = "application/json")

Spring returns JSON.

If multiple converters and formats exist, Spring chooses the best match.

For normal REST APIs:

JSON is the most common response format.

42. Multiple Methods Same Path Different Produces

Example:

@GetMapping(value = "/api/report", produces = "application/json")
public ReportDto reportJson() {
return reportService.getReport();
}
@GetMapping(value = "/api/report", produces = "text/csv")
public String reportCsv() {
return reportService.getReportCsv();
}

Request:

GET /api/report
Accept: application/json

calls:

reportJson()

Request:

GET /api/report
Accept: text/csv

calls:

reportCsv()

43. Ambiguous Mapping

Bad:

@GetMapping("/api/tasks")
public List<TaskDto> list1() {
return taskService.findAll();
}
@GetMapping("/api/tasks")
public List<TaskDto> list2() {
return taskService.findRecent();
}

Both match:

GET /api/tasks

Spring cannot decide.

Usually startup fails with an ambiguous mapping error.

Fix by making mappings different:

@GetMapping("/api/tasks")
public List<TaskDto> list() {
return taskService.findAll();
}

@GetMapping("/api/tasks/recent")
public List<TaskDto> recent() {
return taskService.findRecent();
}

or add conditions carefully.

Memory sentence:

Two identical mappings cause ambiguity.


44. Path Design: Resource-Oriented URLs

Good REST paths:

/api/tasks
/api/tasks/{id}
/api/clients/{clientId}/tasks
/api/clients/{clientId}/tasks/{taskId}

Less good:

/api/getTask
/api/createTask
/api/deleteTask

Why?

Because HTTP method already describes the action.

Good:

GET /api/tasks/1
POST /api/tasks
DELETE /api/tasks/1

Memory sentence:

Use nouns in URLs and HTTP methods for actions.


45. Query Parameters for Filtering, Sorting, Pagination

Good:

GET /api/tasks?status=OPEN&page=0&size=20&sort=createdAt,desc

Controller:

@GetMapping("/api/tasks")
public List<TaskDto> list(
@RequestParam(required = false) String status,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestParam(defaultValue = "createdAt,desc") String sort
) {
return taskService.find(status, page, size, sort);
}

Use query parameters for:

filtering
sorting
pagination
search
optional options

46. Path Variables for Resource Identity

Use path variables for resource identity.

Good:

GET /api/tasks/123

because 123 identifies the task.

Good:

GET /api/clients/10/tasks/99

because 10 identifies the client and 99 identifies the task.

Memory sentence:

Path variables identify resources. Query params filter resources.


47. PathVariable vs RequestParam

SituationUse
Identify one resource@PathVariable
Filter list@RequestParam
Pagination@RequestParam
Sorting@RequestParam
Search keyword@RequestParam
Nested resource ID@PathVariable

Examples:

GET /api/tasks/123

Use:

@PathVariable Long id
GET /api/tasks?status=OPEN

Use:

@RequestParam String status

48. Headers for Metadata

Use headers for request metadata.

Examples:

Authorization
X-Request-Id
X-Correlation-Id
X-Tenant-Id
Accept-Language
Content-Type
Accept

Example:

@GetMapping("/api/tasks")
public List<TaskDto> list(
@RequestHeader("X-Correlation-Id") String correlationId
) {
return taskService.findAll(correlationId);
}

Do not use headers for normal resource identity when path variables are clearer.


49. Common HTTP Headers

HeaderMeaning
Content-Typeformat of request body
Acceptresponse format client wants
Authorizationauthentication credentials
Accept-Languagepreferred language
X-Request-Idrequest tracing
X-Correlation-Iddistributed tracing
X-Tenant-Idtenant context in multi-tenant apps

50. Real Example for Klarsync-Like App

@RestController
@RequestMapping("/api/clients/{clientId}/tasks")
public class ClientTaskController {

@GetMapping
public List<TaskDto> listTasks(
@PathVariable Long clientId,
@RequestParam(required = false) String status,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestHeader(value = "X-Request-Id", required = false) String requestId
) {
return taskService.findClientTasks(clientId, status, page, size, requestId);
}

@PostMapping(
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<TaskDto> createTask(
@PathVariable Long clientId,
@RequestBody CreateTaskRequest request
) {
TaskDto created = taskService.createClientTask(clientId, request);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}
}

Request:

GET /api/clients/10/tasks?status=OPEN&page=0&size=20
X-Request-Id: req-123

Bindings:

clientId = 10
status = OPEN
page = 0
size = 20
requestId = req-123

SituationTypical Status
No matching path404 Not Found
Path exists but HTTP method wrong405 Method Not Allowed
Request body content type unsupported415 Unsupported Media Type
Client asks for unsupported response type406 Not Acceptable
Missing required query parameter400 Bad Request
Path variable conversion fails400 Bad Request
Invalid JSON body400 Bad Request

52. Common Exam Traps

Trap 1

@RequestMapping without method can match many HTTP methods.

Prefer @GetMapping, @PostMapping, etc.


Trap 2

Class-level and method-level paths combine.

@RequestMapping("/api/tasks")
@GetMapping("/{id}")

means:

GET /api/tasks/{id}

Trap 3

@PathVariable reads from the URL path.

@RequestParam reads from the query string.

@RequestHeader reads from headers.

@RequestBody reads from the body.


Trap 4

params is a mapping condition.

@RequestParam is a value binding annotation.


Trap 5

headers is a mapping condition.

@RequestHeader is a value binding annotation.


Trap 6

consumes checks request Content-Type.

produces checks what response type the method can produce.


Trap 7

Wrong Content-Type can cause 415 Unsupported Media Type.

Unsupported Accept can cause 406 Not Acceptable.


Trap 8

Two identical mappings can cause ambiguous mapping errors.


Trap 9

@RequestParam is required by default.


Trap 10

Use query parameters for filtering and pagination.

Use path variables for resource identity.


53. Real Exam Question: @RequestMapping

Question:

What does @RequestMapping do?

Answer:

@RequestMapping maps HTTP requests to controller classes or methods. It can match based on path, HTTP method, request parameters, headers, consumed media type, and produced media type.


54. Real Exam Question: Shortcut Annotations

Question:

What are @GetMapping and @PostMapping?

Answer:

They are shortcut composed annotations for @RequestMapping with a specific HTTP method. @GetMapping maps GET requests, and @PostMapping maps POST requests.


55. Real Exam Question: Class-Level Mapping

Question:

What is the final path?

@RestController
@RequestMapping("/api/tasks")
public class TaskController {

@GetMapping("/{id}")
public TaskDto get(@PathVariable Long id) {
return taskService.findById(id);
}
}

Answer:

GET /api/tasks/{id}

56. Real Exam Question: @PathVariable

Question:

What does @PathVariable do?

Answer:

@PathVariable binds a value from the URL path to a controller method parameter.


57. Real Exam Question: @RequestParam

Question:

What does @RequestParam do?

Answer:

@RequestParam binds a query parameter from the request URL to a controller method parameter.


58. Real Exam Question: Required Query Param

Question:

What happens if a required @RequestParam is missing?

Answer:

Spring usually returns 400 Bad Request.


59. Real Exam Question: @RequestHeader

Question:

What does @RequestHeader do?

Answer:

@RequestHeader binds an HTTP request header value to a controller method parameter.


60. Real Exam Question: params

Question:

What does this mean?

@GetMapping(value = "/api/tasks", params = "status")

Answer:

This method matches only requests to /api/tasks that include a status query parameter.


61. Real Exam Question: headers

Question:

What does this mean?

@GetMapping(value = "/api/tasks", headers = "X-API-Version=2")

Answer:

This method matches only requests with header X-API-Version equal to 2.


62. Real Exam Question: consumes

Question:

What does consumes = "application/json" mean?

Answer:

It means the endpoint accepts requests whose body has Content-Type: application/json.


63. Real Exam Question: produces

Question:

What does produces = "application/json" mean?

Answer:

It means the endpoint can produce a JSON response.


64. Real Exam Question: consumes vs produces

Question:

What is the difference between consumes and produces?

Answer:

consumes describes what request body media type the endpoint accepts, based on Content-Type. produces describes what response media type the endpoint can return, based on content negotiation and the Accept header.


65. Real Exam Question: Ambiguous Mapping

Question:

What happens if two controller methods have the exact same mapping?

Answer:

Spring usually fails to start with an ambiguous mapping error because it cannot decide which method should handle the request.


66. Interview Answer

Question:

Explain request mapping in Spring MVC.

Good answer:

Request mapping is how Spring MVC maps HTTP requests to controller methods. A mapping can match by path, HTTP method, query parameters, headers, request content type through consumes, and response content type through produces. In REST controllers, I usually use shortcut annotations like @GetMapping, @PostMapping, @PutMapping, @PatchMapping, and @DeleteMapping.


67. Interview Answer

Question:

What is the difference between @PathVariable, @RequestParam, @RequestHeader, and @RequestBody?

Good answer:

@PathVariable reads values from the URL path, such as /tasks/{id}. @RequestParam reads query parameters, such as /tasks?page=0. @RequestHeader reads HTTP headers, such as X-Request-Id. @RequestBody reads the HTTP request body and converts it into a Java object, usually from JSON.


68. Interview Answer

Question:

What is the difference between params and @RequestParam?

Good answer:

params is a mapping condition. It controls whether a controller method matches a request. For example, params = "status" means the method only matches if the request has a status query parameter. @RequestParam is used after the method is selected to bind the query parameter value to a Java method parameter.


69. Interview Answer

Question:

What is the difference between consumes and produces?

Good answer:

consumes describes what request body media type the endpoint accepts, usually based on the Content-Type header. For example, consumes = "application/json" means the request body must be JSON. produces describes what response media type the endpoint can return, usually based on the Accept header and content negotiation. For example, produces = "application/json" means the endpoint can return JSON.


70. Interview Answer

Question:

How do you design REST paths?

Good answer:

I use resource-oriented paths with nouns, not action verbs. For example, I use GET /api/tasks/123 instead of /api/getTask. The HTTP method describes the action. I use path variables for resource identity, such as task ID, and query parameters for filtering, sorting, and pagination.


71. Tiny Code Practice

Create this controller:

@RestController
@RequestMapping("/api/clients/{clientId}/tasks")
public class ClientTaskController {

@GetMapping
public List<TaskDto> list(
@PathVariable Long clientId,
@RequestParam(required = false) String status,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestHeader(value = "X-Request-Id", required = false) String requestId
) {
return taskService.find(clientId, status, page, size, requestId);
}

@PostMapping(
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<TaskDto> create(
@PathVariable Long clientId,
@RequestBody CreateTaskRequest request
) {
TaskDto created = taskService.create(clientId, request);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}
}

Request:

GET /api/clients/10/tasks?status=OPEN&page=1&size=5
X-Request-Id: req-999

Questions:

  1. Which method handles the request?
  2. What is clientId?
  3. What is status?
  4. What is page?
  5. What is size?
  6. What is requestId?

Answers:

  1. list
  2. 10
  3. OPEN
  4. 1
  5. 5
  6. req-999

72. Tiny Bug Practice 1

Problem:

@GetMapping("/api/tasks")
public List<TaskDto> list1() {
return taskService.findAll();
}

@GetMapping("/api/tasks")
public List<TaskDto> list2() {
return taskService.findRecent();
}

Question:

What is wrong?

Answer:

Both methods have the same mapping. Spring cannot decide which method should handle GET /api/tasks, so the application can fail with an ambiguous mapping error.


73. Tiny Bug Practice 2

Problem:

@PostMapping(
value = "/api/tasks",
consumes = MediaType.APPLICATION_JSON_VALUE
)
public TaskDto create(@RequestBody CreateTaskRequest request) {
return taskService.create(request);
}

Request:

POST /api/tasks
Content-Type: text/plain

hello

Question:

What happens?

Answer:

The endpoint consumes JSON, but the request sends text/plain. Spring usually returns 415 Unsupported Media Type.


74. Tiny Bug Practice 3

Problem:

@GetMapping("/api/tasks")
public List<TaskDto> list(@RequestParam String status) {
return taskService.findByStatus(status);
}

Request:

GET /api/tasks

Question:

What happens?

Answer:

status is required by default. Since it is missing, Spring usually returns 400 Bad Request.

Fix:

@RequestParam(required = false) String status

or:

@RequestParam(defaultValue = "OPEN") String status

Practice Questions and Answers

Question 1

What does @RequestMapping do?

Answer:

@RequestMapping maps HTTP requests to controller classes or methods. It can match by path, HTTP method, query parameters, headers, consumed media type, and produced media type.


Question 2

Why should I prefer @GetMapping over @RequestMapping for GET endpoints?

Answer:

@GetMapping clearly maps only GET requests. @RequestMapping without a method can match multiple HTTP methods, which is less precise for REST endpoints.


Question 3

Name five shortcut mapping annotations.

Answer:

Five shortcut mapping annotations are:

@GetMapping
@PostMapping
@PutMapping
@PatchMapping
@DeleteMapping

Question 4

How do class-level and method-level mappings combine?

Answer:

The class-level path and method-level path combine to form the final endpoint path. For example, @RequestMapping("/api/tasks") plus @GetMapping("/{id}") becomes GET /api/tasks/{id}.


Question 5

What does @PathVariable read?

Answer:

@PathVariable reads values from the URL path.


Question 6

What does @RequestParam read?

Answer:

@RequestParam reads query parameters from the URL.


Question 7

Is @RequestParam required by default?

Answer:

Yes. @RequestParam is required by default.


Question 8

How can I make a request parameter optional?

Answer:

Use required = false, Optional<T>, or defaultValue.


Question 9

What does @RequestHeader read?

Answer:

@RequestHeader reads HTTP request headers.


Question 10

What does @RequestBody read?

Answer:

@RequestBody reads the HTTP request body and converts it into a Java object.


Question 11

Can one method normally have two @RequestBody parameters?

Answer:

Usually no. An HTTP request has one body, so a method should normally have one @RequestBody object.


Question 12

What does params = "status" mean?

Answer:

params = "status" means the method matches only if the request has a status query parameter.


Question 13

What is the difference between params and @RequestParam?

Answer:

params is a mapping condition that helps choose the controller method. @RequestParam binds the query parameter value to a Java method parameter.


Question 14

What does headers = "X-API-Version=2" mean?

Answer:

It means the method matches only if the request has header X-API-Version with value 2.


Question 15

What is the difference between headers and @RequestHeader?

Answer:

headers is a mapping condition that helps choose the method. @RequestHeader binds a header value to a Java method parameter.


Question 16

What does consumes mean?

Answer:

consumes describes what request body media type the endpoint accepts, based on the Content-Type header.


Question 17

What does produces mean?

Answer:

produces describes what response media type the endpoint can return, based on content negotiation and the Accept header.


Question 18

What is the difference between Content-Type and Accept?

Answer:

Content-Type describes the format of the request body. Accept describes the response format the client wants.


Question 19

What can cause 415 Unsupported Media Type?

Answer:

415 Unsupported Media Type can happen when the request Content-Type is not supported by the endpoint’s consumes condition.


Question 20

What can cause ambiguous mapping?

Answer:

Ambiguous mapping happens when two or more controller methods match the same request and Spring cannot decide which one to use.

Final Memory Sentences

  • @RequestMapping maps HTTP requests to controller methods.
  • Prefer @GetMapping, @PostMapping, @PutMapping, @PatchMapping, and @DeleteMapping for REST APIs.
  • Class-level and method-level mappings combine.
  • @PathVariable reads from the URL path.
  • @RequestParam reads from the query string.
  • @RequestHeader reads from request headers.
  • @RequestBody reads from the HTTP body.
  • @RequestParam is required by default.
  • params is a mapping condition.
  • @RequestParam binds a value.
  • headers is a mapping condition.
  • @RequestHeader binds a value.
  • consumes checks request Content-Type.
  • produces describes response media type.
  • Content-Type describes request body format.
  • Accept describes desired response format.
  • Wrong Content-Type can cause 415.
  • Unsupported Accept can cause 406.
  • Identical mappings can cause ambiguous mapping errors.
  • Use path variables for resource identity.
  • Use query parameters for filtering, sorting, and pagination.