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
id
field is marked as primary key with auto-increment generation strategy. - We use
LocalDate
for 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@Controller
and@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@Valid
annotation in controller method parameters for automatic validation and error responses. -
Error Handling
Implement global exception handlers using@ControllerAdvice
to 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
- Step-by-Step Guide to Java Exception Handling
- How to Serialize and Deserialize Objects in Java
- Introduction to Java Methods and Functions
- Introduction to Java Collections Framework
- Object-Oriented Programming Concepts in Java
- How to Build REST APIs Using Java Spring Boot
- Java String Manipulation Techniques You Need to Know
- Essential Java Syntax for New Developers
- Java Data Types Explained with Examples
- How to Handle File I/O Operations in Java
- How to Use Java Streams for Data Processing
- How to Install Java JDK on Windows and Mac
- How to Read and Write Files Using Java I/O Streams
- Understanding Java Classes and Objects in Simple Terms
- Best Practices for Writing Clean Java Code
- Understanding Java Virtual Machine (JVM) Basics
- Using Java Collections: Lists, Sets, and Maps Overview
- Top Java Programming Tips for Beginners
- How to Write Your First Java Console Application
- How to Connect Java Applications to MySQL Database
- Java Control Structures: If, Switch, and Loops
- How to Connect Java Programs to a MySQL Database
- Tips for Improving Java Application Performance
- Best Practices for Java Memory Management
- How to Debug Java Code Using Popular IDE Tools
- How to Set Up Java Development Environment
- Multithreading Basics: Creating Threads in Java
- How to Debug Java Code Efficiently
- Using Annotations Effectively in Java Development
- Java Programming Basics for Absolute Beginners