Test your REST API knowledge with 20 interview questions covering @RestController, request mapping, validation, exception handling, HATEOAS, versioning, content negotiation, and best practices.
Below are all 20 questions covered in this quiz, grouped by topic. Each question includes the correct answer and a detailed explanation to help you prepare for your next interview.
What is the difference between @Controller and @RestController in Spring Boot?
@RestController combines @Controller and @ResponseBody, so every method returns data directly instead of resolving a view
@RestController is a convenience annotation that combines @Controller and @ResponseBody. With @Controller, methods return view names (e.g., Thymeleaf templates) by default, and you must add @ResponseBody on each method to return serialized data. With @RestController, every handler method automatically serializes its return value into the response body (typically JSON), making it the standard choice for REST APIs.
What is the difference between @RequestMapping and the composed annotations like @GetMapping and @PostMapping?
@GetMapping, @PostMapping, etc. are shortcut annotations that combine @RequestMapping with a specific HTTP method for better readability
@GetMapping is equivalent to @RequestMapping(method = RequestMethod.GET), @PostMapping to @RequestMapping(method = RequestMethod.POST), and so on. These composed annotations were introduced in Spring 4.3 to improve readability and reduce boilerplate. @RequestMapping is still useful when you need to handle multiple HTTP methods on a single handler or set class-level base paths.
Given the following controller method, what does @RequestBody do?
```java
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody User user) {
return ResponseEntity.status(HttpStatus.CREATED).body(userService.save(user));
}
```It deserializes the HTTP request body (e.g., JSON) into the User object using an HttpMessageConverter
@RequestBody tells Spring to deserialize the incoming HTTP request body into the annotated Java object. By default, Spring Boot uses Jackson's MappingJackson2HttpMessageConverter to convert JSON to the target type. The Content-Type header of the request (e.g., application/json) determines which converter is used. If deserialization fails, Spring returns a 400 Bad Request.
Which HTTP status code should a REST API return when a resource is successfully deleted and there is no response body?
204 No Content
204 No Content is the appropriate status code when a deletion succeeds and the server does not return a body. 200 OK is acceptable if the response includes a confirmation body. 202 Accepted is used when the deletion is queued for asynchronous processing. 201 Created is reserved for successful resource creation. Following correct HTTP semantics is a key REST API best practice.
What is the purpose of ResponseEntity in Spring Boot REST APIs?
It represents the entire HTTP response, allowing you to control the status code, headers, and body
ResponseEntity<T> gives you full control over the HTTP response. You can set the status code (e.g., 201 Created, 404 Not Found), add custom headers, and define the response body. For example, ResponseEntity.ok(body), ResponseEntity.status(HttpStatus.CREATED).body(obj), or ResponseEntity.notFound().build(). It is not required -- you can return plain objects and use @ResponseStatus -- but it provides maximum flexibility.
How would you handle a scenario where a REST API needs to return different HTTP status codes based on business logic in a single method?
```java
@PutMapping("/users/{id}")
public ResponseEntity<User> updateOrCreateUser(@PathVariable Long id, @Valid @RequestBody UserDto dto) {
if (userService.exists(id)) {
User updated = userService.update(id, dto);
return ResponseEntity.ok(updated);
} else {
User created = userService.create(dto);
URI location = ServletUriComponentsBuilder.fromCurrentRequest().build().toUri();
return ResponseEntity.created(location).body(created);
}
}
```Use ResponseEntity to dynamically set different status codes (200 OK for updates, 201 Created for new resources) and include a Location header for created resources
ResponseEntity is ideal when a method must return different status codes based on runtime conditions. In this upsert example, the method returns 200 OK when updating an existing resource and 201 Created with a Location header when creating a new one. The Location header (built via ServletUriComponentsBuilder) points to the newly created resource's URI. This pattern follows HTTP/REST conventions precisely and gives clients clear signals about what happened.
How does @Valid work with Bean Validation in a Spring Boot REST controller?
```java
@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @RequestBody UserDto dto) {
return ResponseEntity.ok(userService.create(dto));
}
```@Valid triggers Bean Validation (JSR 380) on the annotated object, and Spring returns 400 Bad Request if constraints like @NotNull, @Size, or @Email are violated
When you annotate a parameter with @Valid, Spring invokes the Bean Validation framework (Hibernate Validator by default) to check constraints declared on the DTO fields, such as @NotNull, @NotBlank, @Size, @Email, @Min, and @Max. If validation fails, Spring throws a MethodArgumentNotValidException and returns a 400 Bad Request response. You can customize the error response using @ExceptionHandler or @ControllerAdvice.
What is the role of @ControllerAdvice and @ExceptionHandler in REST API error handling?
```java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(ex.getMessage()));
}
}
```They provide centralized, global exception handling across all controllers, allowing you to return consistent error responses with appropriate HTTP status codes
@ControllerAdvice (or @RestControllerAdvice, which adds @ResponseBody) defines a global exception handling class. @ExceptionHandler methods within it catch specific exception types thrown by any controller and return structured error responses. This creates a consistent error format across your entire API. You can handle multiple exception types, set HTTP status codes, and include details like error codes, timestamps, and validation messages.
What is @ResponseStatus and how does it differ from using ResponseEntity?
```java
@ResponseStatus(HttpStatus.NO_CONTENT)
@DeleteMapping("/users/{id}")
public void deleteUser(@PathVariable Long id) {
userService.delete(id);
}
```@ResponseStatus sets a fixed HTTP status code at the annotation level, while ResponseEntity allows dynamic control over status, headers, and body at runtime
@ResponseStatus declares a fixed HTTP status code for a handler method or a custom exception class. It is concise but static -- the status code is always the same. ResponseEntity gives you dynamic, runtime control over the status code, headers, and body. Use @ResponseStatus for simple cases with a predictable outcome (e.g., delete always returns 204). Use ResponseEntity when the status or headers depend on logic (e.g., returning 200 or 201 based on conditions).
What is HATEOAS and how does Spring HATEOAS support it?
```java
@GetMapping("/users/{id}")
public EntityModel<User> getUser(@PathVariable Long id) {
User user = userService.findById(id);
return EntityModel.of(user,
linkTo(methodOn(UserController.class).getUser(id)).withSelfRel(),
linkTo(methodOn(UserController.class).getAllUsers()).withRel("users"));
}
```HATEOAS (Hypermedia as the Engine of Application State) embeds navigational links in API responses so clients can discover available actions dynamically, and Spring HATEOAS provides EntityModel, CollectionModel, and link builders to implement it
HATEOAS is a constraint of REST where responses include hypermedia links that guide clients to related resources and available operations. Instead of hardcoding API URLs, clients follow links. Spring HATEOAS provides EntityModel<T> (single resource with links), CollectionModel<T> (collection with links), and helper methods like linkTo() and methodOn() for type-safe link building. This makes APIs more self-descriptive and evolvable.
What are the common strategies for versioning a REST API, and how can they be implemented in Spring Boot?
Common strategies include URI versioning (/api/v1/users), request parameter versioning (?version=1), custom header versioning (X-API-Version: 1), and content negotiation versioning (Accept: application/vnd.api.v1+json)
There are four main API versioning strategies: (1) URI versioning -- /api/v1/users -- is the simplest and most visible. (2) Request parameter -- /api/users?version=1. (3) Custom header -- X-API-Version: 1. (4) Content negotiation -- using the Accept header with a media type like application/vnd.company.v1+json. In Spring Boot, URI versioning uses path mappings, parameter versioning uses the params attribute of @RequestMapping, header versioning uses the headers attribute, and media type versioning uses the produces attribute. URI versioning is most popular due to its simplicity.
How does content negotiation work in Spring Boot REST APIs?
Content negotiation allows the server to return different representations (JSON, XML, etc.) based on the Accept header, and Spring Boot uses HttpMessageConverters to handle the serialization
Content negotiation is the mechanism by which the client specifies the desired response format via the Accept header (e.g., application/json or application/xml). Spring Boot uses a chain of HttpMessageConverter implementations to serialize the response. Jackson (MappingJackson2HttpMessageConverter) handles JSON by default. Adding the jackson-dataformat-xml dependency enables XML support automatically. You can also configure content negotiation via URL suffix or query parameter using ContentNegotiationConfigurer.
How do you implement pagination in a Spring Boot REST API using Spring Data?
```java
@GetMapping("/users")
public Page<User> getUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestParam(defaultValue = "id") String sortBy) {
return userRepository.findAll(PageRequest.of(page, size, Sort.by(sortBy)));
}
```Spring Data provides Pageable and Page<T> abstractions that handle pagination, sorting, and metadata (total pages, total elements) automatically when passed to repository methods
Spring Data provides built-in pagination support through the Pageable interface and Page<T> return type. PageRequest.of(page, size, sort) creates a Pageable that you pass to repository methods like findAll(Pageable). The returned Page<T> includes content, total elements, total pages, current page number, and whether there are next/previous pages. This metadata is serialized into the JSON response, giving clients everything they need to build pagination controls.
What does idempotency mean in the context of REST APIs, and which HTTP methods are idempotent?
An idempotent operation produces the same result regardless of how many times it is called; GET, PUT, DELETE, and HEAD are idempotent, while POST is not
An idempotent HTTP method produces the same server state when called once or multiple times. GET is idempotent because it only reads data. PUT is idempotent because sending the same update repeatedly yields the same resource state. DELETE is idempotent because deleting an already-deleted resource has no further effect. POST is NOT idempotent because each call may create a new resource. Understanding idempotency is crucial for designing reliable APIs, especially for retry logic and distributed systems.
What are the key differences between REST and SOAP?
REST is an architectural style that uses standard HTTP and lightweight formats (JSON), while SOAP is a protocol with strict XML messaging, WSDL contracts, and built-in WS-Security
REST (Representational State Transfer) is an architectural style that leverages HTTP methods, URIs, and lightweight formats like JSON. It is stateless, cacheable, and simple. SOAP (Simple Object Access Protocol) is a protocol that uses XML exclusively, defines operations via WSDL, and supports WS-Security, WS-ReliableMessaging, and ACID transactions. REST is preferred for public APIs and web/mobile applications due to simplicity and performance. SOAP is still used in enterprise environments where strict contracts and advanced security are required.
How would you design a REST API to support both synchronous and asynchronous long-running operations?
```java
@PostMapping("/reports")
public ResponseEntity<Void> generateReport(@RequestBody ReportRequest request) {
String taskId = reportService.submitAsync(request);
URI statusUri = URI.create("/reports/status/" + taskId);
return ResponseEntity.accepted().location(statusUri).build();
}
@GetMapping("/reports/status/{taskId}")
public ResponseEntity<?> getStatus(@PathVariable String taskId) {
TaskStatus status = reportService.getStatus(taskId);
if (status.isComplete()) {
return ResponseEntity.ok(status.getResult());
}
return ResponseEntity.ok(status);
}
```Return 202 Accepted with a Location header pointing to a status endpoint; the client polls the status endpoint until the operation completes, at which point the result is returned
For long-running operations, the recommended REST pattern is: (1) Accept the request and return 202 Accepted with a Location header pointing to a status/polling endpoint. (2) Process the operation asynchronously (using @Async, a message queue, or CompletableFuture). (3) The client polls the status endpoint, which returns progress information. (4) When complete, the status endpoint returns the result or a link to it. This pattern keeps the API responsive, avoids HTTP timeouts, and follows REST conventions. For real-time updates, you can also combine this with Server-Sent Events or WebSockets.
How do you customize Jackson serialization in Spring Boot? For example, how would you exclude null fields from JSON responses?
Configure ObjectMapper properties in application.properties (e.g., spring.jackson.default-property-inclusion=non_null) or use annotations like @JsonInclude, @JsonProperty, and @JsonIgnore on your DTOs
Spring Boot auto-configures a Jackson ObjectMapper that you can customize in several ways: (1) Set spring.jackson.* properties in application.properties (e.g., spring.jackson.default-property-inclusion=non_null). (2) Use annotations on DTOs: @JsonInclude(JsonInclude.Include.NON_NULL) on a class, @JsonIgnore to exclude fields, @JsonProperty to rename fields, @JsonFormat for date formatting. (3) Define a custom Jackson2ObjectMapperBuilderCustomizer or ObjectMapper bean for advanced configuration. These approaches can be combined for fine-grained control.
What happens when Jackson encounters an unknown JSON property during deserialization, and how do you control this behavior?
```java
// Request body: { "name": "John", "unknownField": "value" }
@PostMapping("/users")
public User createUser(@RequestBody User user) { ... }
```Spring Boot's default ObjectMapper is configured to ignore unknown properties (DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES is false), but you can enable strict mode globally via spring.jackson.deserialization.fail-on-unknown-properties=true or per-class with @JsonIgnoreProperties(ignoreUnknown = false)
By default, Spring Boot configures Jackson to ignore unknown JSON properties (FAIL_ON_UNKNOWN_PROPERTIES = false), which differs from standalone Jackson's default. This is a deliberate choice for API resilience -- clients can send extra fields without breaking. To enforce strict deserialization, set spring.jackson.deserialization.fail-on-unknown-properties=true in application.properties. For per-class control, use @JsonIgnoreProperties(ignoreUnknown = false) on the DTO class. Strict mode is useful when you want to catch typos or unexpected fields during development.
How do you document a Spring Boot REST API using OpenAPI (Swagger)?
```java
@Operation(summary = "Get user by ID", description = "Returns a single user")
@ApiResponse(responseCode = "200", description = "User found")
@ApiResponse(responseCode = "404", description = "User not found")
@GetMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
// ...
}
```Add the springdoc-openapi dependency, which automatically generates an OpenAPI spec from your controllers, and use annotations like @Operation and @ApiResponse for additional documentation
springdoc-openapi (the successor to SpringFox) scans your Spring Boot controllers at runtime and generates an OpenAPI 3.0 specification automatically. The spec is available at /v3/api-docs, and an interactive Swagger UI is served at /swagger-ui.html. You can enrich the generated docs with annotations: @Operation for endpoint summary and description, @ApiResponse for response codes, @Parameter for parameter descriptions, and @Schema for model documentation. This keeps documentation in sync with the code.
What is the difference between @PathVariable and @RequestParam, and when should you use each?
```java
// Path variable: /users/42
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) { ... }
// Request param: /users?status=active&page=0
@GetMapping("/users")
public Page<User> getUsers(@RequestParam String status, @RequestParam int page) { ... }
```@PathVariable extracts values from the URI path for resource identification, while @RequestParam reads query string parameters for filtering, sorting, and optional criteria
@PathVariable binds a value from the URL path template (e.g., /users/{id}) and is used for identifying a specific resource. @RequestParam binds query string parameters (e.g., /users?status=active) and is used for filtering, pagination, sorting, and optional parameters. @RequestParam supports default values via defaultValue and can be made optional with required=false. Use @PathVariable for mandatory resource identifiers and @RequestParam for optional query criteria.
Take the interactive quiz and get your score with a personalized topic breakdown.
Start the Quiz20 questions · 30 min
Java20 questions · 30 min
Java20 questions · 30 min
Java20 questions · 30 min
Java20 questions · 30 min
Java20 questions · 30 min
Spring Boot20 questions · 30 min
Spring Boot20 questions · 30 min
Spring Boot20 questions · 30 min
Spring Boot20 questions · 30 min
Spring Boot20 questions · 30 min
DevOps20 questions · 30 min
Join thousands of developers mastering in-demand skills with Amigoscode. Try it free today.