Introduction

In 2000, Roy Fielding proposed Representational State Transfer (REST) as an architectural approach to designing web services. REST is an architectural style for building distributed systems based on hypermedia. REST is independent of any underlying protocol and is not necessarily tied to HTTP.

What is REST

REST stands for representational state transfer. It is a set of constraints that set out how an API (application programming interface) should work.

REST API Design Principles

  • Uniform Interface: REST APIs are designed around resources, which are any kind of object, data, or service that can be accessed by the client. A resource has an identifier, which is a URI that uniquely identifies that resource.
    Use Noun and not verb to represent a resource
    In general, it helps to use plural nouns

  • Client-Server: Client and Server are independent of each others and the only way the client interacts is through the URI of the resources.
    Client and server can evolve independently.
    Client and server can be implemented in different tech stack.

  • Stateless : REST APIs use a stateless request model. HTTP requests should be independent and may occur in any order. The only place where information is stored is in the resources themselves, and each request should be an atomic operation.
    Being stateless means REST API can scale easily.

  • Cacheable: response to a request be implicitly or explicitly labeled as cacheable or non-cacheable.

  • Layered System: Client and Server should not be tightly coupled and if required and added any intermediate layer the API still should work.

Spring Boot REST API example

REST is an acronym for REpresentational State Transfer. In this article, we will walk through a sample REST application built using Spring Boot. This application does not use any database to store data, all the data is in memory. We will expose a few REST endpoints. Main purpose of this article is to demonstrate how to build REST API's using Spring boot.

Application Details

This application is about building a backend for a Blog software and exposing two REST API endpoints.
Following two endpoints both returns response in JSON format.
/blogapi/blogs : Returns list of blogs
/blogapi/blogs/ID : Returns details of a specific blog
Technology Used
  • Spring Boot 2.2.6.RELEASE
  • Logback 1.2.3
  • Maven 3
  • Java 11
  • Jackson 2.10.3

Project Structure


Code Reference

Maven pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<artifactId>com.bootng.rest</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>war</packaging>
	<name>Spring Boot Rest</name>
	<description>Springboot Rest App</description>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.6.RELEASE</version>
		<relativePath />
	</parent>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- junit 5 -->
		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-engine</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.mockito</groupId>
			<artifactId>mockito-core</artifactId>
			<version>2.19.0</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-api</artifactId>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<addResources>true</addResources>
				</configuration>
				<executions>
					<execution>
						<goals>
							<goal>repackage</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>
BlogStory Model
BlogStory model class which represent a blog entry.
package com.bootng.model;

public class BlogStory {
  private String id;
  private String name;
  private String summary;
  private String description;
  private String category;
  public BlogStory() {
  }
  public BlogStory (String name, String category, String summary) {
    this.id = name.replaceAll(" ","_");
    this.name = name;
    this.summary = summary;
    this.category = category;
    this.description = summary + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt "
        + "ut labore et dolore magna aliqua. "
        + "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
        + " Duis aute irure dolor in reprehenderit in voluptate velit esse cillum "
        + "dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
        + "sunt in culpa qui officia deserunt mollit anim id est laborum" ;   
  }
// Setters
 
}
BlogService Class
Service class which returns list of available blogs. Blog with an id etc.
@Service
public class BlogService {
  List category = Arrays.asList("Technical", "Travel", "Food", "Finance", "Entertainment");
  List stories = new ArrayList();
  {
    stories.add(new BlogStory("Java 11", "Technical", "Java 11 Blog"));
    stories.add(new BlogStory("Java 14", "Technical", "Java 14 Blog"));
    stories.add(new BlogStory("Asia Travel", "Travel", "Places to visit in Asia"));
    stories.add(new BlogStory("Europe Travel", "Travel", "Places to visit in Europe"));
    stories.add(new BlogStory("Japan Travel", "Travel", "Places to visit in Japan"));
    stories.add(new BlogStory("Asian Food", "Food", "Asian Food......"));
  }

  public BlogStory getBlogStory(String id) throws AppException {
    return stories.stream().filter(story -> id.equals(story.getId())).findAny().orElse(null);
  }

  public List getBlogStory() throws AppException {
    return stories;
  }

  public void addStory(BlogStory newStory) throws AppException {
    this.stories.add(newStory);
  }

  public List getBlogTags() throws AppException {
    return category;
  }
}
Main Application Class
Spring Boot's main application class.
@ComponentScan({"com.bootng"})
@SpringBootApplication
public class RestApplication {
  public static void main(String args[]) {
    SpringApplication.run(RestApplication.class, args);
  }
}
BlogAPIController Controller Class
Controller class which exposes the two endpoints
GET /blogapi/blogs
and GET /blogapi/blogs/ID
@Controller annotation is used to mark this class as a Controller.
@RequestMapping is used to map the request paths "/blogs" to getBlogSotries method and /blog/ID to getBlogStory method.
In both cases we are mapping both the paths to HTTP GET verb by using method = RequestMethod.GET
@ResponseBody is used to convert the result to JSON (as we specified by produces=MediaType.APPLICATION_JSON_VALUE)
@Controller
@RequestMapping("/blogapi")
public class BlogAPIController {
private static final Logger log = LoggerFactory.getLogger(BlogAPIController.class);
@Autowired
BlogService blogService;
ResponseEntity apiResponse = new ResponseEntity(newStory, HttpStatus.OK);
    return apiResponse;
}

@RequestMapping(value = {"/blogs"}, method = RequestMethod.GET,
      produces = MediaType.APPLICATION_JSON_VALUE)
  public @ResponseBody ResponseEntity> getBlogStories() {
    log.info("inside getBlogStories GET method");
    List blogStory = null;
    ResponseEntity> apiResponse;
    try {
      blogStory = blogService.getBlogStory();
      apiResponse = new ResponseEntity>(blogStory, HttpStatus.OK);
    } catch (AppException e) {
      apiResponse =
          new ResponseEntity>(blogStory, HttpStatus.INTERNAL_SERVER_ERROR);
      e.printStackTrace();
    }
    return apiResponse;
  }

@RequestMapping(value = {"/blogs"}, method = RequestMethod.GET,
      produces = MediaType.APPLICATION_JSON_VALUE)
  public @ResponseBody ResponseEntity getBlogStory(@PathParam(value = "") String id) {
    log.info("inside blog GET method");
    BlogStory blogStory = null;
    ResponseEntity apiResponse;
    try {
      blogStory = blogService.getBlogStory(id);
      if (blogStory == null)
        apiResponse = new ResponseEntity(blogStory, HttpStatus.NOT_FOUND);
      else
        apiResponse = new ResponseEntity(blogStory, HttpStatus.OK);
    } catch (AppException e) {
      apiResponse = new ResponseEntity(blogStory, HttpStatus.INTERNAL_SERVER_ERROR);
      e.printStackTrace();
    }
    return apiResponse;
  }
}

Start Application

Run Application
Build the project using mvn clean install and then run it with mvn spring-boot:run
mvn clean install
mvn spring-boot:run

Call REST API's using CURL

CURL: Get list of Blogs
Using curl we can get list of blogs from the /blogs endpoint
curl -X GET  http://localhost:8080/blogapi/blogs 
CURL: Get specific blog details
Get a specific blog with id "Java_14" by calling /blogs/Java_14
curl -X GET localhost:8080/blogapi/blogs/Java_14
Git Source Code
  • git clone https://github.com/siddharthagit/spring-boot-references
  • cd springboot-rest
  • mvn clean install
  • mvn spring-boot:run

    Conclusion

    In this article, we used Springs RestController annotation to build the API. With Spring boot we can use other frameworks like Jersey, Restlet, etc also to build API.