a woman holding up a sticker that says get some api

How to create a REST API in Spring Boot?

Let’s say you want to create an ecommerce store.

And you want to expose REST APIs to the end users to do CRUD(Create, Read , Update and Delete) operations on your store items.

You can do this with minimal effort in Spring Boot.

Let’s create the REST APIs.

Creating a REST API in Spring Boot is pretty straightforward.

Spring has provided clean abstractions to implement the same.

Here are the steps:

  1. Create a spring boot project
  2. Add spring-boot-starter-web dependency – this has all the logic to build REST APIs for you.
  3. Create a class and annotate it with @RestController annotation.
  4. Create a method and annotate it with @PostMapping or @GetMapping or @PutMapping or @DeleteMapping depending on the type of HTTP method you want to implement.
  5. Return a Java Object as response – this will be automatically converted into a JSON by Spring by default.

In a production environment we would use a database to store the items , here though for this example we will use an in memory data structure : the array list.

So once your application is shut down your data is gone!

We will see in another chapter how to connect to a persistent data store,

Let’s look at this in detail:

1.Create a Spring Boot project:

Create a spring boot project using spring initializr( https://start.spring.io) or using Spring Tool Suite (through New Spring Starter Project menu)

2. Add dependency:

Any new code you want to plugin to you spring app , there is probably a dependency provided for it by Spring Boot.

spring-boot-starter-web has all the necessary code to let you create REST APIs in Spring Boot.

So add it in your pom.xml (gradle file if you are using gradle build file)

<dependency>

<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

You can also add the above dependency while creating the project using spring initializr

All set to add necessary code now.

3. Create a class with @RestController annotation

Spring provides @RestController annotation to mark a class as a collection of REST APIs.

package com.example.demo;

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

@RestController

public class RestAPI {
}

4. Create HTTP methods

There are four main HTTP methods:

POST – to add a resource

GET – to get a resource

PUT – to update a resource

DELETE – to delete a resource

In our case the resources are the store items.

CRUD operations neatly fit into the above HTTP methods:

POST – Create (C)

GET – Read (R)

PUT – Update (U)

DELETE – Delete (D)

Now let’s implement the HTTP methods.

POST method:

We will use POST method to add products .

@PostMapping("/product")

public List<Product> addProduct(@RequestBody Product product) {

product.setId(products.size() + 1);
this.products.add(product);
return products;
}

As you see you need to use @PostMapping annotation and give the relative path value (“/product”). This path value will be appended to the application domain url (http://localhost:8080/product) in case of your local machine.

You also need to use @RequestBody annotation to represent the input from the user.

This by default represents JSON input.

Remember Spring is an opinionated framework so it gives defaults.

Majority of the HTTP APIs used in enterprise applications accept JSON as input and return JSON as output so Spring has provided them as defaults.

You can explicitly specify the media type if otherwise using “produces” attribute for the response type and “consumes” attribute for the input type:

@PostMapping(path =  "/product",consumes = MediaType.APPLICATION_JSON_VALUE ,produces = MediaType.APPLICATION_JSON_VALUE)

GET method:

We will use GET method to get a particular product.

@GetMapping("/product/{id}")

public Product getProduct(@PathVariable int id) {

for(Product p:products) {
if(p.getId() == id) {
return p;
}
}
return null;
}

In the above code we are getting the product id as a path variable added within curly braces {id} .

You also need to use @PathVariable annotation as a parameter in the method to retrieve the path variable.

PUT method:

We will use PUT method to update a product’s details:

This is very similar to POST method except that to identify the product we also send the product id along with the request:

@PutMapping("/product")

public List<Product> updateProduct(@RequestBody Product product) {

this.products.forEach(p -> {
if (p.getId() == product.getId()) {
              p.setName(product.getName());                          p.setQuantity(product.getQuantity());
}
});
return products;
}

DELETE method:

We will delete a product using this method:

@DeleteMapping("/product/{id}")

public List<Product> deleteProduct(@PathVariable int id) {

  Product toRemove = null;
for (Product p : products) {

if (p.getId() == id) {
toRemove = p;
}
}
if (toRemove != null) {
this.products.remove(toRemove);
}
return products;
}

Again we are passing path variable in this method just like in GET method to identify the product.

Passing Request Parameters:

Instead of passing path variables which get appended to the url path , we can also pass request parameters of the form http://application-url.com/id=1

Here is an example of how to do it in Spring Boot:

@GetMapping("/api/product")

public Product getProductById(@RequestParam("id") int id) {

for(Product p:products) {
if(p.getId() == id) {
return p;
}
}
return null;
}

I have given a different relative path here (“/api/product”) as (“/product”) path has already been taken for GET method using Path Variable.

You need to pass the request parameter using @RequestParam annotation as shown in the above method. You can ignore the value passed in the parentheses (“id”) , In this case the name of the parameter will be taken as the same as that of the method argument.

Here is the entire REST Controller code:

package com.example.demo;
import java.util.ArrayList;
import java.util.List;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController

public class RestAPI {
List<Product> products = new ArrayList<Product>();

@GetMapping("/product")

public List<Product> getAllProducts() {
        return products;

}

@GetMapping("/product/{id}")

public Product getProduct(@PathVariable int id) {

for (Product p : products) {

if (p.getId() == id) {
return p;
}
}
return null;

}

@GetMapping("/api/product")

public Product getProductById(@RequestParam("id") int id) {

for (Product p : products) {
if (p.getId() == id) {
return p;
}
}
return null;
}

@PostMapping(path = "/product")

public List<Product> addProduct(@RequestBody Product product) {
product.setId(products.size() + 1);

this.products.add(product);
return products;
}

@PutMapping("/product")

public List<Product> updateProduct(@RequestBody Product product) {
this.products.forEach(p -> {
if (p.getId() == product.getId()) {
p.setName(product.getName());
p.setQuantity(product.getQuantity());

}

});
return products;
}

@DeleteMapping("/product/{id}")

public List<Product> deleteProduct(@PathVariable int id) {
Product toRemove = null;

for (Product p : products) {
if (p.getId() == id) {
toRemove = p;
}
}

if (toRemove != null) {
this.products.remove(toRemove);
}
return products;
}
}

To note:

As you might have noticed we can use the same URI (“/product”) for the different HTTP methods but we can’t use the same URI for the same HTTP method (we have three GET operations in the above code with different URI)

We have used HTTP method specific annotation in the above examples (@PostMapping for POST , @GetMapping for GET) etc. You can also use a generic annotation @RequestMapping and pass in the type of HTTP method as a parameter to the annotation)

We have returned a Java object as a response in the above examples.

Spring internally converts it into a JSON and sends back to the user along with the HTTP Status “OK”

We can also return “ResponseEntity” object provided by Spring and send our own HTTP status in it.

Now run the application and the REST APIs get created.

You can use a REST client tool like postman to test the various HTTP operations.

That is the basic overview of how to create REST APIs in Spring Boot.

But it doesn’t stop there ,

What we have created are more or less just WEB APIs ,

To be recognized as a REST API there are more standards to be followed as laid down by the creator of REST API (Roy T Field)

According to him:

  1. REST APIs should represent a collection of resources and you do CRUD operations on your resources using those APIs. It should not be specific to your business logic (Don’t have REST APIs with names like /deliverProducts, /buyItem etc)
  2. REST APIs should have different URI and HTTP method for each operation on the resources (Each CRUD operation will have a different URI/HTTP method like in the above example)
  3. REST API should provide links in its response to the different operations that can be performed on the resource (From the response you can get the link to perform other CRUD operations)
  4. REST API should provide cacheability
  5. REST API should follow client server architecture with business code implemented on the server and only client specific code implemented on the client
  6. REST API should have a layered system . For example you can introduce an API gateway between client and server as a new layer and your REST APIs should work seamlessly

https://fullstackdeveloper.guru/2021/10/14/rest-api-vs-http-api-are-your-rest-apis-really-rest-apis/

To sum up ,

We saw how to create REST APIs using the annotations provided by Spring.

We saw how to represent HTTP operations (GET , POST , PUT and DELETE)

That’s it!


Posted

in

, ,

by

Comments

Leave a Reply

Discover more from The Full Stack Developer

Subscribe now to keep reading and get access to the full archive.

Continue reading