10 Java REST Interview Questions and Answers
Prepare for your next interview with our comprehensive guide on Java RESTful web services, featuring expert insights and practical examples.
Prepare for your next interview with our comprehensive guide on Java RESTful web services, featuring expert insights and practical examples.
Java RESTful web services have become a cornerstone in modern software development, enabling seamless communication between distributed systems. Leveraging the robustness of Java and the flexibility of REST architecture, developers can create scalable, maintainable, and efficient APIs that power a wide range of applications, from enterprise solutions to mobile apps.
This article offers a curated selection of interview questions designed to test your understanding and proficiency in Java REST. By working through these questions, you will gain deeper insights into key concepts and best practices, ensuring you are well-prepared to demonstrate your expertise in any technical interview setting.
In RESTful services, status codes indicate the result of a client’s request. Common codes include:
Exception handling in a Spring Boot REST application can be centralized using @ControllerAdvice
and @ExceptionHandler
. @ControllerAdvice
allows handling exceptions across the application, while @ExceptionHandler
defines methods for specific exceptions.
Example:
import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.context.request.WebRequest; @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<?> resourceNotFoundException(ResourceNotFoundException ex, WebRequest request) { ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false)); return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND); } @ExceptionHandler(Exception.class) public ResponseEntity<?> globalExceptionHandler(Exception ex, WebRequest request) { ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false)); return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR); } }
In this example, GlobalExceptionHandler
handles exceptions like ResourceNotFoundException
and general exceptions, returning appropriate HTTP statuses.
In a Spring Boot REST application, request parameters and payloads can be validated using the Java Bean Validation API (JSR 380) with annotations like @NotNull
, @Size
, @Min
, and @Max
. Spring Boot integrates these validations and provides mechanisms to handle errors.
Example:
import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; public class User { @NotNull(message = "Name cannot be null") @Size(min = 2, max = 30, message = "Name must be between 2 and 30 characters") private String name; @NotNull(message = "Email cannot be null") private String email; // Getters and Setters }
In your controller, use the @Valid
annotation to trigger validation:
import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import org.springframework.http.ResponseEntity; @RestController @RequestMapping("/users") public class UserController { @PostMapping public ResponseEntity<String> createUser(@Valid @RequestBody User user) { return ResponseEntity.ok("User is valid"); } }
To handle validation errors, use an @ExceptionHandler
method:
import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<String> handleValidationExceptions(MethodArgumentNotValidException ex) { StringBuilder errors = new StringBuilder(); ex.getBindingResult().getAllErrors().forEach(error -> errors.append(error.getDefaultMessage()).append("\n")); return new ResponseEntity<>(errors.toString(), HttpStatus.BAD_REQUEST); } }
Pagination and sorting in RESTful services manage large datasets efficiently. Pagination uses query parameters like page
and size
, while sorting uses a sort
parameter.
Example:
import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class ItemController { private final ItemRepository itemRepository; public ItemController(ItemRepository itemRepository) { this.itemRepository = itemRepository; } @GetMapping("/items") public Page<Item> getItems( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size, @RequestParam(defaultValue = "id,asc") String[] sort) { Sort.Direction direction = Sort.Direction.fromString(sort[1]); PageRequest pageRequest = PageRequest.of(page, size, Sort.by(direction, sort[0])); return itemRepository.findAll(pageRequest); } }
In this example, ItemController
handles pagination and sorting using query parameters.
HATEOAS (Hypermedia as the Engine of Application State) ensures clients interact with a network application through hypermedia provided by servers. It includes hypermedia links in responses to guide clients on available actions.
Example:
import org.springframework.hateoas.EntityModel; import org.springframework.hateoas.Link; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class UserController { @GetMapping("/users/{id}") public EntityModel<User> getUser(@PathVariable Long id) { User user = userService.findById(id); EntityModel<User> resource = EntityModel.of(user); resource.add(Link.of("/users/" + id + "/orders", "orders")); return resource; } }
In this example, getUser
returns an EntityModel
with a link to related resources.
Versioning in a RESTful API maintains backward compatibility while allowing evolution. Strategies include:
/api/v1/resource
./api/resource?version=1
.Accept: application/vnd.myapi.v1+json
.Accept
header, e.g., Accept: application/vnd.myapi+json; version=1
.Each method has its pros and cons, with URI versioning being simple but potentially cluttered, while header versioning keeps URLs clean but can be complex.
Optimizing RESTful service performance involves several strategies:
Caching strategies for RESTful services include:
Rate limiting in a RESTful API controls the number of requests a client can make within a time frame. A common approach is the token bucket algorithm, where each client has a bucket with tokens replenished at a fixed rate.
Example:
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; public class RateLimiter { private final int maxRequests; private final long refillInterval; private final ConcurrentHashMap<String, TokenBucket> buckets = new ConcurrentHashMap<>(); public RateLimiter(int maxRequests, long refillInterval) { this.maxRequests = maxRequests; this.refillInterval = refillInterval; } public boolean allowRequest(String clientId) { TokenBucket bucket = buckets.computeIfAbsent(clientId, k -> new TokenBucket(maxRequests, refillInterval)); return bucket.allowRequest(); } private static class TokenBucket { private int tokens; private final int maxTokens; private long lastRefillTimestamp; private final long refillInterval; public TokenBucket(int maxTokens, long refillInterval) { this.tokens = maxTokens; this.maxTokens = maxTokens; this.refillInterval = refillInterval; this.lastRefillTimestamp = System.nanoTime(); } public synchronized boolean allowRequest() { refillTokens(); if (tokens > 0) { tokens--; return true; } return false; } private void refillTokens() { long now = System.nanoTime(); long elapsedTime = now - lastRefillTimestamp; if (elapsedTime > refillInterval) { tokens = Math.min(maxTokens, tokens + (int) (elapsedTime / refillInterval)); lastRefillTimestamp = now; } } } }
Content negotiation in RESTful services determines the best representation of a resource using HTTP headers. The client specifies preferences with headers like Accept
, Accept-Language
, and Accept-Encoding
, and the server selects the appropriate representation.
Key headers include:
If the server cannot provide a suitable representation, it may respond with a 406 Not Acceptable
status code.