Friday, August 17, 2018

Create a REST API with Spring Boot

In this post, I will explain how to create a simple a REST API with Spring Boot

Spring Boot
Spring Boot is a framework that provides inbuilt configuration that a Java web application can run without the XML configurations that come with a typical Spring application and it does not require a traditional WAR deployment. Spring Boot makes it easy Spring based Applications that you can just run.


REST Endpoints

Our application will expose the following endpoints:

GET /bookstore/book - Retrieves all books
GET /bookstore/book{id}  - Retrieves a specific boo based on ID
POST /bookstore/book  - Creates a new book
PUT /bookstore/book{id}  - Updates an existing book
DELETE /bookstore/book/{id} - Removes a specific book based on ID
DELETE /bookstore/book - Removes all books

Creating SpringBootApplication class

package com.libmgmt.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages={"com.libmgmt"})
public class MySpringBootApplication {

public static void main(String[] args) {
SpringApplication.run(MySpringBootApplication.class, args);
}
}

Creating BookController

package com.libmgmt.model;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;
import com.libmgmt.exception.BookException;
import com.libmgmt.model.Book;
import com.libmgmt.service.BookService;

@RestController
@RequestMapping("/")
public class BookController {

@Autowired
BookService bookService;

@RequestMapping(value = "/book", method = RequestMethod.GET)
public ResponseEntity<List<Book>> findAllBooks() {
List<Book> books = bookService.findAllBooks();
if (books.isEmpty()) {
return new ResponseEntity<List<Book>>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<List<Book>>(books, HttpStatus.OK);
}

@RequestMapping(value = "/book/{id}", method = RequestMethod.GET)
public ResponseEntity<?> findBook(@PathVariable("id") long id) {
Book book = bookService.findById(id);
if (book == null) {
return new ResponseEntity<BookException>(
new BookException("ERROR: Book Id " + id
+ " not found"), HttpStatus.NOT_FOUND);
}
return new ResponseEntity<Book>(book, HttpStatus.OK);
}

@RequestMapping(value = "/book", method = RequestMethod.POST)
public ResponseEntity<?> createBook(@RequestBody Book book,
UriComponentsBuilder ucBuilder) {

if (bookService.isBookExist(book)) {
return new ResponseEntity<BookException>(
new BookException("ERROR: Book name ="
+ book.getName() + " already exist."),
HttpStatus.CONFLICT);
}
bookService.saveBook(book);

HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/api/book/{id}")
.buildAndExpand(book.getId()).toUri());
return new ResponseEntity<String>(headers, HttpStatus.CREATED);
}

@RequestMapping(value = "/book/{id}", method = RequestMethod.PUT)
public ResponseEntity<?> updateBook(@PathVariable("id") long id,
@RequestBody Book book) {

Book currentBook = bookService.findById(id);

if (currentBook == null) {
return new ResponseEntity<BookException>(
new BookException("ERROR: Id =" + id
+ " not found."), HttpStatus.NOT_FOUND);
}

currentBook.setName(book.getName());
currentBook.setAuthor(book.getAuthor());
currentBook.setPrice(book.getPrice());
return new ResponseEntity<Book>(currentBook, HttpStatus.OK);
}

@RequestMapping(value = "/book/{id}", method = RequestMethod.DELETE)
public ResponseEntity<?> deleteBook(@PathVariable("id") long id) {

Book book = bookService.findById(id);
if (book == null) {
return new ResponseEntity<BookException>(
new BookException("ERROR: Id =" + id
+ " not found."), HttpStatus.NOT_FOUND);
}
bookService.deleteBookById(id);
return new ResponseEntity<Book>(HttpStatus.NO_CONTENT);
}

@RequestMapping(value = "/book", method = RequestMethod.DELETE)
public ResponseEntity<Book> deleteAllBooks() {

bookService.deleteAllBooks();
return new ResponseEntity<Book>(HttpStatus.NO_CONTENT);
}

}

Creating Book Model

package com.libmgmt.model;

public class Book {
private long id;
private String name;
private String author;
private float price;

public Book() {
id = 0;
}

public Book(long id, String name, String author, float price) {
this.id = id;
this.name = name;
this.author = author;
this.price = price;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getAuthor() {
return author;
}

public void setAuthor(String author) {
this.author = author;
}

public float getPrice() {
return price;
}

public void setPrice(float price) {
this.price = price;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (id ^ (id >>> 32));
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Book other = (Book) obj;
if (id != other.id)
return false;
return true;
}


}

Creating Book Service 

package com.libmgmt.service;

import java.util.List;
import com.libmgmt.model.Book;

public interface BookService {

public Book findById(long id);
public Book findByName(String bookName);
public void saveBook(Book book);
public void updateBook(Book book);
public void deleteBookById(long id);
public List<Book> findAllBooks();
public void deleteAllBooks();
public boolean isBookExist(Book Book);


}

Creating Book Mock Service Implementation

package com.libmgmt.service;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.stereotype.Service;
import com.libmgmt.model.Book;

@Service
public class BookServiceImpl implements BookService {

private static final AtomicLong counter = new AtomicLong();

private static List<Book> books;

static {
init();
}

private static void init() {
List<Book> bookList = new ArrayList<Book>();
bookList.add(new Book(counter.incrementAndGet(), "Java", "Andrew",
100.0f));
bookList.add(new Book(counter.incrementAndGet(),
"Data Structure & Algorithm", "John", 200.f));
books = bookList;
}

public Book findById(long id) {
for (Book book : books) {
if (book.getId() == id) {
return book;
}
}
return null;
}

public void saveBook(Book book) {
book.setId(counter.incrementAndGet());
books.add(book);
}

public void updateBook(Book book) {
int index = books.indexOf(book);
books.set(index, book);
}

public void deleteBookById(long id) {
for (Iterator<Book> iter = books.iterator(); iter.hasNext();) {
Book book = iter.next();
if (book.getId() == id) {
iter.remove();
}
}
}

public List<Book> findAllBooks() {
return books;
}

public void deleteAllBooks() {
books.clear();
}

public boolean isBookExist(Book book) {
return findByName(book.getName()) != null;
}

public Book findByName(String bookName) {
for (Book book : books) {
if (book.getName().equalsIgnoreCase(bookName)) {
return book;
}
}
return null;
}

}

Creating Book Exception 

package com.libmgmt.exception;

public class BookException {
private String errorMessage;

public BookException(String errorMessage) {
this.errorMessage = errorMessage;
}

public String getErrorMessage() {
return errorMessage;
}

}


Book Services Curl

Get All books
curl -X GET -i 'http://127.0.0.1:8080/bookstore/book'

Get Single Book
curl -X GET -i 'http://127.0.0.1:8080/bookstore/book/1'

Create Book
curl -X POST -H 'Content-Type: application/json' -i 'http://127.0.0.1:8080/bookstore/book' --data '{"id":3,"name":"C++","author":"E Balagrusamy","price":100.0}'

Update Book 
curl -X PUT -H 'Content-Type: application/json' -i 'http://127.0.0.1:8080/bookstore/book/3' --data '{"id":3,"name":"C++","author":"E Balagrusamy","price":120.0}'

Delete Single Book
curl -X DELETE -H 'Content-Type: application/json' -i 'http://127.0.0.1:8080/bookstore/book/5'

Delete All Books

curl -X DELETE -H 'Content-Type: application/json' -i 'http://127.0.0.1:8080/bookstore/book/3' --data '{"id":4,"name":"Angular JS","author":"E Balagrusamy","price":120.0}'

Create a REST API with Spring Boot

In this post, I will explain how to create a simple a REST API with Spring Boot Spring Boot Spring Boot is a framework that provides inbuil...