When a server exposes an API, request parameters and payloads play a key role in managing resources. Today we'll cover:
- Handling Query Parameters: filters and sorting.
- Working with Path Variables: dynamic URI segments.
- How to handle parameter-related errors.
And of course we'll write code! Because theory without practice is like a method without an implementation.
What are Query Parameters?
Let's start with Query Parameters. These are parameters the client passes in the query string after the ? character. They are used for filtering, sorting, searching data, and other request refinements.
Example URL with Query Parameters:
https://api.myapp.com/products?category=electronics&sort=price&order=asc
- category=electronics: indicates a filter by category "electronics".
- sort=price: signals that we're sorting by price.
- order=asc: clarifies that the sort is ascending.
The @RequestParam annotation
To handle Query Parameters in Spring we use the @RequestParam annotation. Let's look at a code example:
@RestController
@RequestMapping("/products")
public class ProductController {
@GetMapping
public List<Product> getProducts(
@RequestParam(required = false) String category,
@RequestParam(defaultValue = "name") String sort,
@RequestParam(defaultValue = "asc") String order
) {
// Filtering and sorting logic
return productService.getProducts(category, sort, order);
}
}
@RequestParam(required = false): the parameter is not required. If the client doesn't passcategory, it will benull.defaultValue: sets a default value if the parameter is missing from the request.
When a request is sent to /products?category=clothing, in the getProducts method the variable category will be "clothing", and sort and order will take their default values.
What are Path Variables?
Path Variables are parts of the URI that carry dynamic values.
Imagine we have a REST API for managing products and we need to get a product by its ID. Example URI:
https://api.myapp.com/products/42
Here 42 is the product identifier and we want to extract it from the path. For that we use the @PathVariable annotation.
The @PathVariable annotation
Spring lets you "pluck" these values out of the URI like this:
@RestController
@RequestMapping("/products")
public class ProductController {
@GetMapping("/{id}")
public Product getProductById(@PathVariable Long id) {
// Logic to get product by ID
return productService.getProductById(id);
}
}
When the client sends GET /products/42, the id variable will get the value 42.
Combining @RequestParam and @PathVariable
Now, as programmers say, let's level up. We can combine them! For example, you can do a combo like this:
- The URI contains a dynamic value (
id) to identify the resource. - Query Parameters are used for extra tuning.
Example: getting user orders with a filter
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{userId}/orders")
public List<Order> getUserOrders(
@PathVariable Long userId,
@RequestParam(required = false) String status,
@RequestParam(defaultValue = "date") String sort
) {
// Logic for filtering user's orders
return orderService.getUserOrders(userId, status, sort);
}
}
Request:
GET /users/101/orders?status=completed&sort=price
In this example:
userIdwill be101.statuswill be"completed".sortwill be"price".
Validating request parameters
Clients won't always send correct data. For example, what if the user ID in the request is abc, which is obviously invalid?
Error handling
Spring will automatically return an error if a @PathVariable or @RequestParam doesn't match the expected type. For example:
@GetMapping("/{id}")
public Product getProductById(@PathVariable Long id) {
return productService.getProductById(id);
}
The request GET /products/abc will cause:
HTTP 400 Bad Request
To make error handling nicer, you can use the @ExceptionHandler annotation:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<String> handleTypeMismatch(MethodArgumentTypeMismatchException ex) {
return ResponseEntity
.badRequest()
.body("Invalid parameter: " + ex.getName());
}
}
Now the error will be friendlier to the client:
HTTP 400 Bad Request
Body: Invalid parameter: id
Practice: REST API example for working with books
Let's build a REST API for books. The API will allow:
- Retrieve a book by ID.
- Search books by genre with sorting.
Entity class Book
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String genre;
private double price;
// Getters and setters
}
Repository BookRepository
@Repository
public interface BookRepository extends JpaRepository<Book, Long> {
List<Book> findByGenre(String genre, Sort sort);
}
Service BookService
@Service
public class BookService {
@Autowired
private BookRepository bookRepository;
public Book getBookById(Long id) {
return bookRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Book not found!"));
}
public List<Book> getBooksByGenre(String genre, String sortField) {
Sort sort = Sort.by(Sort.Direction.ASC, sortField);
return bookRepository.findByGenre(genre, sort);
}
}
Controller BookController
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookService bookService;
@GetMapping("/{id}")
public Book getBookById(@PathVariable Long id) {
return bookService.getBookById(id);
}
@GetMapping
public List<Book> getBooksByGenre(
@RequestParam(required = false) String genre,
@RequestParam(defaultValue = "title") String sort
) {
return bookService.getBooksByGenre(genre, sort);
}
}
Now:
GET /books/1will return the book with ID 1.GET /books?genre=fantasy&sort=pricewill return all books in the "fantasy" genre, sorted by price.
Common mistakes and fixes
@PathVariableis missing from the URI. Make sure the path variable is declared in the route (for example,/{id}).- Wrong parameter data type. If
idexpects aLongbut the client sent a string, you'll get a 400 error. - Missing required Query Parameters. Make sure you use
required = falseif the parameter is optional.
At this point you've mastered working with Query Parameters and Path Variables. Your REST APIs will now be more functional and flexible. Keep going to the next lesson and don't forget to test your APIs!
GO TO FULL VERSION