Creating a Simple REST Endpoint with Spring Boot
- Published on
In this post I want to demonstrate how easy it is to create a REST endpoint with Spring Boot and to demonstrate it we will create a simple REST endpoint for our fridge 🧊. It will be a CRUD endpoint that will allow listing creating, updating and deleting products.
- Bootstrapping (Generating) a New Application
- Creating a REST Endpoint with @RestController
- Specifying a Base Path for the REST Endpoint with @RequestMappings
- HTTP GET Mapping via @GetMapping
- HTTP POST Mapping via @PostMapping
- HTTP PUT Mapping via @PutMapping
- HTTP DELETE Mapping via @DeleteMapping
- Conclusion
The full source code for this post is available in my lab repository:
Bootstrapping (Generating) a New Application
The first thing we need to do to create a REST endpoint using Spring Boot is to boostrap a new application. This can be done using Spring Initializr and I covered this in my previous post, which you can find here - How to Create a New Application with Spring Boot.
Many IDEs use Spring Initializr to generate a new application, here is how I did it in IntelliJ Idea:
@RestController
Creating a REST Endpoint with To create a REST endpoint we need to create a Java class and annotate it with @RestController
. It is important that this class is created in the same package or sub-package of the main application class. If it is not, Spring Boot will not locate this class automatically and will need extra configuration to find it.
package com.example.fridgeservice;
import org.springframework.web.bind.annotation.*;
@RestController
public class FridgeController {
}
@RestController
annotation tells Spring that this class is special and will respond to requests. As its name suggests, this class is a web @Controller
, so Spring considers it when handling incoming web requests.
Once we have our RestController, the only thing that is left to finish our implementation is to add methods that will respond to different HTTP requests and mark them with special Spring annotations.
@RequestMappings
Specifying a Base Path for the REST Endpoint with In the controller we will create methods that can be accessed by a specific path and request method. If we know ahead of time that all of our endpoints are going to have the same base path, we can create that path at the class level using the @RequestMapping
annotation:
package com.example.fridgeservice;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("fridge") // translates to http://localhost/fridge
public class FridgeController {
}
This tells Spring that any mapping created in this controller will start with the path /fridge
unless overridden.
Before we create methods in our controller that can respond to requests, we will need some sample data to work with. This data could come from a file, database, or a simple in-memory storage.
In this example, we declare a new instance variable called storedProducts
that will hold a List<String>
. It will be initialized it with some products in constructor:
package com.example.fridgeservice;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("fridge")
public class FridgeController {
private List<String> storedProducts;
public FridgeController() {
storedProducts = new ArrayList<>();
storedProducts.add("Milk");
storedProducts.add("Pizza");
storedProducts.add("Mineral Water");
}
// list
// add
// replace
// take
}
Let's add methods that will respond to our HTTP requests.
@GetMapping
HTTP GET Mapping via The first method will return a list of all products stored in our fridge:
@GetMapping
public List<String> list() {
return storedProducts;
}
@GetMapping
tells Spring that this method will be accessed using the GET
request. @GetMapping
is a composed annotation that acts as a shortcut for @RequestMapping(method = RequestMethod.GET)
.
At this point we have an endpoint that responds to GET
requests:
@PostMapping
HTTP POST Mapping via We need a way to add new products to our fridge. It makes sense to use POST
request for that. Let's use the following JSON format as a payload:
{
"productName": "Juice"
}
Here is the implementation:
// add
@PostMapping
public void add(@RequestBody Map<String, String> payload) {
storedProducts.add(payload.get("productName"));
}
The @PostMapping
annotation tells Spring that this method will accept a POST
request to /fridge
. The @RequestBody
annotation tells Spring to map what is in the request body to the variable payload. Because JSON is key/value pair, a sensible data type is Map<String, String>
. Finally, in the body of the method itself we will get a product name and add it to the list of stored products.
Let's verify it by issuing a POST request.
If your application is still running in the first terminal tab, stop it with Ctrl-C and re-run using the following command:
./mvnw spring-boot:run
Now we have a way of adding new products to our fridge.
@PutMapping
HTTP PUT Mapping via We can use a similar approach to replace stored products. Because we have a simple string representation for stored products, we simply pass the old product name and a new product name for replacement. This way our controller method can look up the current value and replace that object in the list. The JSON payload will look like this:
{
"oldProductName": "Milk",
"newProductName": "Beer"
}
My implementation:
// replace
@PutMapping
public void replace(@RequestBody Map<String, String> payload) {
String oldProduct = payload.get("oldProductName");
String newProduct = payload.get("newProductName");
if (storedProducts.contains(oldProduct)) {
storedProducts.set(storedProducts.indexOf(oldProduct), newProduct);
}
}
The @PutMapping
annotation tells Spring that this method will respond to PUT
requests on /fridge
. The @RequestBody
annotation works exactly the same as it did on the add
method.
Let's verify if it works.
If your application is still running in the first terminal tab, stop it with Ctrl-C and re-run using the following command:
./mvnw spring-boot:run
It works!
@DeleteMapping
HTTP DELETE Mapping via Finally, we will need to take a product from our fridge and DELETE
request will serve for this purpose:
// take
@DeleteMapping
public void take(@RequestParam String productName){
storedProducts.remove(productName);
}
The @DeleteMapping
annotation tells Spring that this method will respond to DELETE
requests on /fridge
endpoint. In this scenario, we don't need to send a JSON request body, just a simple request parameter. When we want to take (delete) a product, we would send a DELETE
request to a URL like /fridge?productName=Pizza
. The @RequestParam
will assign the request parameter to the variable productName.
Example:
Do not forget to restart the application after new changes!
The final code for our REST endpoint (the full source code can be found in my lab repository):
package com.example.fridgeservice;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* A simple CRUD endpoint to manage products in the fridge. It shows how easy it is to create a REST API with Spring Boot.
*/
@RestController
@RequestMapping("fridge")
public class FridgeController {
private List<String> storedProducts;
public FridgeController() {
storedProducts = new ArrayList<>();
storedProducts.add("Milk");
storedProducts.add("Pizza");
storedProducts.add("Mineral Water");
}
// list
@GetMapping
public List<String> list() {
return storedProducts;
}
// add
@PostMapping
public void add(@RequestBody Map<String, String> payload) {
storedProducts.add(payload.get("productName"));
}
// replace
@PutMapping
public void replace(@RequestBody Map<String, String> payload) {
String oldProduct = payload.get("oldProductName");
String newProduct = payload.get("newProductName");
if (storedProducts.contains(oldProduct)) {
storedProducts.set(storedProducts.indexOf(oldProduct), newProduct);
}
}
// take
@DeleteMapping
public void take(@RequestParam String productName){
storedProducts.remove(productName);
}
}
Conclusion
As you can see it is very easy to create a REST endpoint with Spring Boot, you just need to use special animations and the rest (JSON serialization for example) will be handled by Spring behind the scenes.
Do not forget to Subscribe to my RSS feed for new updates!