In the world of modern web development, REST APIs (Representational State Transfer Application Programming Interfaces) have become the backbone of communication between client and server applications. Java Spring Boot, a powerful and widely used framework, simplifies building production-grade RESTful services with minimal boilerplate code. In this article, you’ll learn how to build a simple REST API using Java Spring Boot from scratch.
What is Spring Boot?
Spring Boot is an open-source framework that makes it easy to create stand-alone, production-grade Spring-based applications. It takes an opinionated view of the Spring platform and third-party libraries, offering defaults and auto-configuration to accelerate development.
Key features include:
- Embedded servers (e.g., Tomcat or Jetty), so you don’t need to deploy WAR files.
- Starter dependencies for quick setup.
- Production-ready features like metrics, health checks, and externalized configuration.
- Minimal configuration to get started quickly.
What is a REST API?
REST (Representational State Transfer) defines a set of architectural principles for designing networked applications. A REST API exposes resources (data and functionality) via endpoints that clients can interact with using standard HTTP methods like GET, POST, PUT, DELETE.
Typical characteristics:
- Stateless communication
- Uniform interface using HTTP methods
- Resource-based URLs
- Support for various data formats (commonly JSON)
Prerequisites
Before diving in, make sure you have the following installed:
- Java Development Kit (JDK) 11 or higher
- Maven or Gradle build tool (we’ll use Maven)
- An IDE such as IntelliJ IDEA, Eclipse, or VS Code
- Basic knowledge of Java and web development
Step 1: Initialize Your Spring Boot Project
You can create a new Spring Boot project by using the Spring Initializr.
- Project: Maven Project
- Language: Java
- Spring Boot version: Choose the latest stable release (e.g., 3.x)
- Group:
com.example - Artifact:
demo-rest-api - Packaging: Jar
- Java: 11 or above
Add the following dependencies:
- Spring Web
- Spring Data JPA
- H2 Database (for in-memory testing)
Click Generate to download your project zip file. Extract it and open it in your IDE.
Alternatively, you can generate the project from IDE plugins or use command-line tools.
Step 2: Understand the Project Structure
Once your project is loaded, you will see a basic structure:
src/
+- main/
+- java/com/example/demo_rest_api/
| +- DemoRestApiApplication.java
+- resources/
+- application.properties
+- data.sql (optional)
The DemoRestApiApplication.java contains the main method to start your Spring Boot application.
Step 3: Define the Model
Let’s build a simple API for managing Books. Each book will have an id, title, author, and publishedDate.
Create a new package called model inside com.example.demo_rest_api:
package com.example.demo_rest_api.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import java.time.LocalDate;
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String author;
private LocalDate publishedDate;
// Constructors
public Book() {}
public Book(String title, String author, LocalDate publishedDate) {
this.title = title;
this.author = author;
this.publishedDate = publishedDate;
}
// Getters and setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public LocalDate getPublishedDate() {
return publishedDate;
}
public void setPublishedDate(LocalDate publishedDate) {
this.publishedDate = publishedDate;
}
}
Notes:
- We are using JPA annotations to mark this class as an entity mapped to a database table.
- The
idfield is marked as primary key with auto-increment generation strategy. - We use
LocalDatefor date handling.
Step 4: Create Repository Interface
Create a new package named repository. Inside it, define an interface for CRUD operations:
package com.example.demo_rest_api.repository;
import com.example.demo_rest_api.model.Book;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface BookRepository extends JpaRepository<Book, Long> {
}
This interface extends Spring Data JPA’s JpaRepository, which automatically provides implementations for common database operations such as save, findAll, findById, deleteById etc.
Step 5: Build the Service Layer
Though optional for simple apps, adding a service layer is good practice for business logic separation.
Create a package named service, then add:
package com.example.demo_rest_api.service;
import com.example.demo_rest_api.model.Book;
import com.example.demo_rest_api.repository.BookRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class BookService {
private final BookRepository bookRepository;
@Autowired // Constructor injection
public BookService(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
public List<Book> getAllBooks() {
return bookRepository.findAll();
}
public Optional<Book> getBookById(Long id) {
return bookRepository.findById(id);
}
public Book saveBook(Book book) {
return bookRepository.save(book);
}
public boolean deleteBook(Long id) {
if(bookRepository.existsById(id)){
bookRepository.deleteById(id);
return true;
}
return false;
}
}
The service encapsulates business logic and communicates with the repository layer.
Step 6: Create REST Controller
Now create a package called controller and define your REST endpoints there.
package com.example.demo_rest_api.controller;
import com.example.demo_rest_api.model.Book;
import com.example.demo_rest_api.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/books")
public class BookController {
private final BookService bookService;
@Autowired
public BookController(BookService bookService){
this.bookService = bookService;
}
// GET /api/books - Retrieve all books
@GetMapping
public List<Book> getAllBooks() {
return bookService.getAllBooks();
}
// GET /api/books/{id} - Retrieve single book by ID
@GetMapping("/{id}")
public ResponseEntity<Book> getBookById(@PathVariable Long id){
return bookService.getBookById(id)
.map(book -> ResponseEntity.ok().body(book))
.orElse(ResponseEntity.notFound().build());
}
// POST /api/books - Add new book
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Book createBook(@RequestBody Book book){
return bookService.saveBook(book);
}
// DELETE /api/books/{id} - Delete book by ID
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteBook(@PathVariable Long id){
boolean deleted = bookService.deleteBook(id);
if(deleted){
return ResponseEntity.noContent().build();
} else{
return ResponseEntity.notFound().build();
}
}
}
Explanation:
- The class is annotated with
@RestController, which combines@Controllerand@ResponseBody. - We map requests starting with
/api/books. - Methods handle GET (all books and single by ID), POST (create new), and DELETE (remove by ID).
Spring Boot automatically converts Java objects to JSON responses thanks to its built-in HTTP message converter.
Step 7: Configure In-Memory Database
To test our API without setting up an external database, configure H2 in-memory database.
Edit the file src/main/resources/application.properties and add:
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# Enable H2 console access at /h2-console endpoint (optional)
spring.h2.console.enabled=true
# Show SQL statements in logs (optional)
spring.jpa.show-sql=true
# Hibernate ddl auto mode - create tables automatically on startup
spring.jpa.hibernate.ddl-auto=update
This configuration sets up an in-memory database that lives only during application runtime. When you restart your app, data resets.
You can visit http://localhost:8080/h2-console after running your app to interact with the database manually.
Step 8: Run Your Application
Run the main application class DemoRestApiApplication.java. Most IDEs have a Run button or right-click > Run As > Java Application.
Alternatively, use Maven in terminal:
./mvnw spring-boot:run
Your REST API server should start on default port 8080.
Step 9: Test Your API Endpoints
You can test your API via tools like Postman, curl commands, or browser plugins.
Testing GET all books
curl -X GET http://localhost:8080/api/books
Expected result: An empty JSON array ([]) if no books are added yet.
Testing POST new book
curl -X POST http://localhost:8080/api/books \
-H "Content-Type: application/json" \
-d '{"title":"Spring Boot Guide","author":"John Doe","publishedDate":"2023-04-01"}'
Response should be HTTP status 201 Created along with created JSON object including generated ID.
Testing GET single book by ID
curl -X GET http://localhost:8080/api/books/1
Expected response should be JSON representation of the first book.
Testing DELETE a book
curl -X DELETE http://localhost:8080/api/books/1
If successful, returns status code 204 No Content.
Optional Testing UI Using Postman or Swagger UI
You can also integrate Swagger UI for interactive API documentation. This requires adding extra dependencies such as springdoc-openapi-ui but is beyond scope here.
Step 10: Improve Your API (Optional Enhancements)
Here are some ways you can evolve your API once basic CRUD works:
-
Validation
Add annotations like@NotNull,@Size, etc., from Jakarta Bean Validation. Use@Validannotation in controller method parameters for automatic validation and error responses. -
Error Handling
Implement global exception handlers using@ControllerAdviceto handle invalid inputs or other exceptions gracefully. -
DTOs (Data Transfer Objects)
Separate entity model from request/response models by creating DTOs for better API contract control. -
Pagination & Sorting
Leverage Spring Data’s paging features on repository methods to handle large datasets efficiently. -
Security
Secure your endpoints with Spring Security for authentication and authorization. -
Documentation
Use OpenAPI/Swagger annotations for auto-generating API docs accessible via web UI. -
Testing
Write unit tests for controllers and services using libraries like JUnit and Mockito; integration tests using MockMvc.
Conclusion
Building a simple REST API with Java Spring Boot is straightforward due to its convention-over-configuration approach and robust ecosystem. You learned how to set up a project from scratch; define entities; create repositories; implement service logic; expose REST endpoints; configure an in-memory database; and test your API using HTTP requests.
This foundation serves as a launchpad into more complex RESTful services tailored to real-world requirements like security, scalability, deployment pipelines, microservices architecture, message queues, caching layers, and more. Embrace these basics today and explore deeper as you build applications that power dynamic modern software solutions!
Related Posts:
Java
- How to Connect Java Applications to MySQL Database
- Introduction to Java Methods and Functions
- Java String Manipulation Techniques You Need to Know
- How to Use Java Streams for Data Processing
- Introduction to Java Collections Framework
- Using Java Collections: Lists, Sets, and Maps Overview
- Essential Java Syntax for New Developers
- How to Read and Write Files Using Java I/O Streams
- How to Debug Java Code Using Popular IDE Tools
- Java Programming Basics for Absolute Beginners
- Multithreading Basics: Creating Threads in Java
- Understanding Java Classes and Objects in Simple Terms
- How to Deploy Java Applications on AWS Cloud
- How to Handle File I/O Operations in Java
- Top Java Programming Tips for Beginners
- How to Install Java JDK on Windows and Mac
- How to Write Your First Java Console Application
- Java Control Structures: If, Switch, and Loops
- Using Annotations Effectively in Java Development
- How to Implement Inheritance in Java Programming
- Java Data Types Explained with Examples
- Understanding Java Virtual Machine (JVM) Basics
- How to Use Java Arrays Effectively
- How to Build REST APIs Using Java Spring Boot
- Step-by-Step Guide to Java Exception Handling
- Exception Handling in Java: Try, Catch, Finally Explained
- Java Interface Usage and Best Practices
- How to Implement Multithreading in Java
- Best Practices for Java Memory Management
- How to Debug Java Code Efficiently