Module: Building REST APIs

@PathVariable, @RequestParam

This section dives into how to handle different ways of passing data to your Spring Boot REST APIs: using @PathVariable and @RequestParam. These annotations are crucial for building flexible and user-friendly APIs.

Understanding Request Parameters

Before we jump into the code, let's understand why we need these. When a client (like a web browser or another application) makes a request to your API, it often needs to send data along with it. This data can be sent in a few ways:

  • As part of the URL: This is common for identifying a specific resource. For example, /users/123 where 123 is the user ID.
  • As query parameters: These are appended to the URL after a ? and are used for filtering, sorting, or providing additional information. For example, /products?category=electronics&sort=price.

@PathVariable and @RequestParam help Spring Boot extract this data from the request and make it available to your controller methods.

@PathVariable: Extracting Data from the URL Path

@PathVariable is used to extract values directly from the URL path. It's ideal for identifying specific resources.

Example:

Let's create a simple API endpoint to retrieve a user by their ID.

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/{userId}")
    public String getUser(@PathVariable("userId") Long userId) {
        // In a real application, you'd fetch the user from a database here.
        return "User with ID: " + userId;
    }
}

Explanation:

  • @GetMapping("/users/{userId}"): This maps GET requests to the /users/{userId} path. The {userId} part is a placeholder for the user ID.
  • @PathVariable("userId") Long userId: This annotation tells Spring Boot to extract the value from the URL path at the {userId} placeholder and bind it to the userId parameter of the getUser method. The "userId" inside the annotation specifies which placeholder to bind to. Long specifies the expected data type.

How to test it:

If you send a GET request to http://localhost:8080/users/123, the getUser method will be called with userId set to 123. The API will return "User with ID: 123".

Important Considerations:

  • Data Type: Ensure the data type of the @PathVariable parameter matches the expected type in the URL. Spring Boot will attempt to convert the value, and if it fails, it will throw an exception.
  • Required: By default, @PathVariable parameters are required. If the placeholder is missing in the URL, Spring Boot will throw an exception. You can make it optional by using required = false within the annotation (e.g., @PathVariable("userId") Long userId). However, you'll need to handle the case where the parameter is missing in your code.

@RequestParam: Extracting Data from Query Parameters

@RequestParam is used to extract values from query parameters in the URL. It's useful for filtering, sorting, or providing optional information.

Example:

Let's create an API endpoint to retrieve products based on a category.

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProductController {

    @GetMapping("/products")
    public String getProducts(@RequestParam(value = "category", defaultValue = "all") String category) {
        // In a real application, you'd fetch products from a database based on the category.
        return "Products in category: " + category;
    }
}

Explanation:

  • @GetMapping("/products"): This maps GET requests to the /products path.
  • @RequestParam(value = "category", defaultValue = "all") String category: This annotation tells Spring Boot to extract the value from the query parameter named category and bind it to the category parameter of the getProducts method.
    • value = "category": Specifies the name of the query parameter to extract.
    • defaultValue = "all": Provides a default value if the category query parameter is not present in the request. If the parameter is missing, category will be set to "all".

How to test it:

  • http://localhost:8080/products: The API will return "Products in category: all" (because the category parameter is missing, so the default value is used).
  • http://localhost:8080/products?category=electronics: The API will return "Products in category: electronics".
  • http://localhost:8080/products?category=books&sort=price: The API will return "Products in category: books" (only the category parameter is used in this example).

Important Considerations:

  • Data Type: Similar to @PathVariable, ensure the data type of the @RequestParam parameter matches the expected type in the query string. Spring Boot will attempt to convert the value.
  • Required: By default, @RequestParam parameters are optional. If the parameter is missing, the parameter in your method will be set to null (for object types) or the default value (if specified). You can make a @RequestParam parameter required by setting required = true within the annotation. If a required parameter is missing, Spring Boot will throw an exception.
  • Multiple Parameters: You can have multiple @RequestParam annotations in a single method to extract multiple query parameters.

Combining @PathVariable and @RequestParam

You can use both @PathVariable and @RequestParam in the same controller method to handle both path variables and query parameters.

Example:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ItemController {

    @GetMapping("/items/{itemId}")
    public String getItemDetails(@PathVariable("itemId") Long itemId, @RequestParam(value = "details", defaultValue = "basic") String details) {
        // Fetch item details based on itemId and details level
        return "Item ID: " + itemId + ", Details Level: " + details;
    }
}

How to test it:

  • http://localhost:8080/items/456: Returns "Item ID: 456, Details Level: basic"
  • http://localhost:8080/items/456?details=full: Returns "Item ID: 456, Details Level: full"

Summary

  • @PathVariable extracts data from the URL path. Use it for identifying specific resources.
  • @RequestParam extracts data from query parameters. Use it for filtering, sorting, or providing optional information.
  • You can combine both annotations in a single method to handle both types of request parameters.
  • Pay attention to data types and whether parameters are required or optional. Use defaultValue for @RequestParam to provide sensible defaults.

By mastering @PathVariable and @RequestParam, you'll be well-equipped to build robust and flexible REST APIs with Spring Boot.