Switch to:
6 ways to pass parameters to a REST API in Spring Boot (Java)

6 ways to pass parameters to a REST API in Spring Boot (Java)

Accepting parameters for server-side processing is a fundamental requirement of REST APIs.

Often confusion is made between the different ways of passing parameters, using them incorrectly. This article aims to clarify once and for all the differences between these approaches and explain how to use them correctly in Spring Boot.

We will explore 6 ways to pass parameters to a REST endpoint and how we can accept and read them in Spring Boot with Java.

1. Query Parameters

Query parameters are added to the URL after the question mark.

They are commonly used for filtering, sorting or to provide additional context to the REST endpoint. Their use is simple and immediate, but it is important to be aware of their limitations.

Query parameters are easy to use and readable, ideal for predictable requests and for passing optional data. However, they can be problematic if they contain sensitive data, since these can be exposed in server logs or browser history. Furthermore, some browsers and servers impose limits on URL length, making it difficult to pass very extensive parameters.

// Example – Retrieval of products by category

Let’s imagine we want to get all products belonging to a certain category.


// Endpoint definition
@GetMapping("/products")
public List<Product> getProductsByCategory(@RequestParam String category) {
  return productService.findByCategory(category);
}

// Access to the Endpoint
curl http://localhost:8080/products?category=electronics
2. Path Variables

Path variables are placeholders in the URI that are replaced with real values at the time of the request.

They are perfect for unique identifiers, such as product ID or username, ensuring clear and descriptive URLs. However, they are not suitable for optional parameters, since their absence could invalidate the request.

Using path variables makes APIs more readable and structured, but improper use, such as nesting too many levels of path with parameters, can lead to complex and difficult to manage URLs.

// Example – Retrieval of a specific product

We want to get the information on a specific product given its ID.


// Endpoint definition
@GetMapping("/products/{id}")
public Product getProductById(@PathVariable Long id) {
  return productService.findById(id);
}

// Access to the Endpoint
curl http://localhost:8080/products/101
3. Matrix Variables

Matrix variables allow passing parameters within the URI, separated by a semicolon.

They are useful for applications that require a hierarchical structure of resources, offering an orderly way to filter data directly in the URL. However, they are poorly supported by browsers and some HTTP clients, and require additional configuration in Spring Boot.

If well used, matrix variables improve the readability and flexibility of REST APIs, but their scarce diffusion makes them less practical than other methods.

// Example – Advanced product filtering

We want to filter products by category and maximum price.


// Endpoint definition
@GetMapping("/products")
public List<Product> getFilteredProducts(@MatrixVariable String category, @MatrixVariable double maxPrice) {
  return productService.findByCategoryAndPrice(category, maxPrice);
}

// Access to the Endpoint
curl http://localhost:8080/products;category=electronics;maxPrice=500.00;
4. Request Body

The request body is the ideal approach for sending complex payloads to POST or PUT endpoints.

It allows transmitting structured objects without length limitations, unlike query parameters. However, it is not idempotent: each call can modify the server state, making it unsuitable for read-only operations.

Using the request body is essential for creating and updating resources, but its non-transparent nature can make debugging and data tracking more difficult.

// Example – Creation of new products

We want to add one or more products via a POST request.


// Endpoint definition
@PostMapping("/products/add")
public ResponseEntity<String> addProducts(@RequestBody List<Product> products) {
  productService.addProducts(products);
  return ResponseEntity.ok("Products added successfully");
}

// Access to the Endpoint
curl --header "Content-Type: application/json" \
 --request POST \
 --data '[{"name": "Laptop","category": "electronics","price": 1200.00}, {"name": "Smartphone","category": "electronics","price": 800.00}]' \
 http://localhost:8080/products/add
5. Request Headers

HTTP headers allow passing additional information such as authentication tokens or configuration preferences. This method is useful for transmitting sensitive data securely, avoiding exposing it in the URL.

However, parameters in request headers are not directly visible, making debugging and request management more difficult. Furthermore, some network configurations or proxies can alter or block certain headers.

// Example – Retrieval of a product with authentication

We want to get a specific product but require an authentication token in the header.


// Endpoint definition
@GetMapping("/products/{id}")
public Product getProductById(@PathVariable Long id, @RequestHeader("Authorization") String authToken) {
  return productService.findByIdWithAuth(id, authToken);
}

// Access to the Endpoint
curl -H "Authorization: Bearer <_authToken_>" http://localhost:8080/products/101
6. Cookies

The use of cookies is an effective solution to maintain state between successive requests, for example to track user sessions or save preferences.

Being separate from the URL, cookies offer greater security than query parameters. However, they are subject to restrictions in modern browsers for privacy reasons and can be blocked by some security configurations.

Using cookies in a stateless REST API is not always recommended, since it could go against the principle of request independence. However, for applications that require stateful interactions, they can represent an effective solution.

// Example – Retrieval of products based on user preference

We want to get the recommended products for the user based on their preferences saved in a cookie.


// Endpoint definition
@GetMapping("/products/recommended")
public List<Product> getRecommendedProducts(@CookieValue("UserPreference") String userPreference) {
  return productService.findRecommended(userPreference);
}

// Access to the Endpoint
curl --cookie "UserPreference=gaming" http://localhost:8080/products/recommended

We have explored 6 ways to pass parameters to REST endpoints in Spring Boot and how to access them.

Each method has advantages and limitations, and the choice of the right approach depends on the specific needs of the project.

Correct use of these mechanisms improves the security, readability and maintainability of APIs.

Ranieri Vannozzi

The author

Ranieri Vannozzi

Freelance software developer and consultant

I have been writing code since 2008, working on enterprise development, cloud-native architectures and technical leadership. On HeroHubs I write about what I run into every day on real projects, from code to architecture and artificial intelligence.

Article written with AI assistance and reviewed by the author.

Related Posts

Performant npm: the package manager that rethinks node_modules

Development

September 2026

Performant npm: the package manager that rethinks node_modules

Performant npm is not just a faster npm. The global store with hard links and the strict node_modules structure change the way a JavaScript project declares and uses its dependencies.

Conventional Commits: the commit message as a technical document

Development

June 2026

Conventional Commits: the commit message as a technical document

Writing commit messages freely is a convention that forms through inertia. Conventional Commits replaces it with a structure that generates value automatically.

Brute force protection: authentication that holds

Development

June 2026

Brute force protection: authentication that holds

A brute force attack is not sophisticated, but it is persistent. Building a solid defence is an architectural question first, a configuration question second.

Why is ignoring package-lock architectural suicide?

Development

May 2026

Why is ignoring package-lock architectural suicide?

Many developers treat the lock file as background noise in commits. In reality, it is the only thing standing between your code and a sudden crash in production.

Biome: the modern toolchain that simplifies web development

Development

October 2025

Biome: the modern toolchain that simplifies web development

Discover Biome: the unified toolchain for linting, formatting, and code analysis in JavaScript/TypeScript. Benefits, integration, and productivity for modern developers.

Test driven development: a silent ally for software heroes

Development

October 2025

Test driven development: a silent ally for software heroes

Learn about Test Driven Development (TDD): benefits, Red-Green-Refactor cycle, practical examples, and how TDD and BDD improve software quality and maintainability.

Astro: islands architecture and hybrid rendering for performant content

Development

October 2025

Astro: islands architecture and hybrid rendering for performant content

A guide to Astro: the modern framework for static and hybrid sites, islands architecture, server-first rendering, SEO, performance, and integration with React, Vue, and Svelte.

Feature flags: the key to safe, controlled, and continuous releases

Development

October 2025

Feature flags: the key to safe, controlled, and continuous releases

Learn how feature flags revolutionize software releases: gradual rollout, instant rollback, A/B testing, and best practices for DevOps and CI/CD.

Pull and merge requests: same goals but different approaches

Development

September 2025

Pull and merge requests: same goals but different approaches

Pull requests vs merge requests: differences, advantages, and best practices for code review on GitHub and GitLab, with a focus on DevOps and team collaboration.