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);
}
}
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}'
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}'