# Spring Boot Optional Path Variables

By Atta Ur Rehman Shah (https://attacomsian.com/about). Published Feb 17, 2020, updated Sep 24, 2022. Topics: Spring Boot.
Canonical URL: https://attacomsian.com/blog/spring-boot-optional-path-variables

> A short guide to learning how to use optional path variables in a Spring Boot web controller.

It is common in Spring Boot to perform more than one task in a single controller method. In this short article, you'll learn how to use optional path variables in Spring Boot to handle more than one type of request. 

By design in Spring Boot, it is impossible to have optional path variables. Let us say you have the following controller method that handles GET requests on the `/todos/{id}` endpoint:

```java
@GetMapping(value = {"/todos", "/todos/{id}"})
public @ResponseBody Object fetchTodos(@PathVariable Long id) {
    if (id == null) {
        // return single todo
        return todoRespository.findById(id);
    } else {
        // return all todos
        return todoRespository.findAll();
    }
}
```

We want to be sure that the above controller method works for both `/todos` and `/todos/1` requests. If the `id` path variable is present, we just fetch a todo by ID and send it back to the client. Otherwise, simply returns all todos.

Right now, if you skip the `id` path variable and call the `/todos` endpoint directly, Spring Boot will throw an exception. One way to avoid this exception is to **have two methods**, one with the path variable and then another without, as shown below:

```java
// two methods - not recommended
@GetMapping("/todos/{id}")
public @ResponseBody Todo fetchTodoById(@PathVariable Long id) {
    return todoRespository.findById(id);
}

@GetMapping("/todos")
public @ResponseBody List<Todo> fetchAllTodos() {
    return todoRespository.findAll();
}
```

Technically, the above approach should work fine, but what if you have a bunch of optional path variables? This approach can quickly lead to almost duplicate code blocks.

## Using `required` Attribute

If you are using Spring Boot 2 and higher, the easiest and most efficient way to make any `@PathVariable` optional is by setting the `required` attribute to `false` as shown below:

```java
@GetMapping(value = {"/todos", "/todos/{id}"})
public @ResponseBody Object fetchTodos(@PathVariable(required = false) Long id) {
    if (id == null) {
        return todoRespository.findById(id);
    } else {
        return todoRespository.findAll();
    }
}
```

That's all you need to do. Now, the above method can handle both types of requests without any exceptions.

## Using Java 8 `Optional` Class

Another way to make a path variable optional in Spring Boot (with Spring 4+) is by using the Java 8 `Optional` class:

```java
@GetMapping(value = {"/todos", "/todos/{id}"})
public @ResponseBody Object fetchTodos(@PathVariable Optional<Long> id) {
    if (id.isPresent()) {
        return todoRespository.findById(id.get());
    } else {
        return todoRespository.findAll();
    }
}
```

The `Optional` class is a special container object which may or may not contain a non-null value. If a value is present, the `isPresent()` method will return `true` and `get()` will return the value.
