Spring Boot is one of the most popular frameworks for building REST APIs in Java. It removes most of the configuration required by traditional Spring applications, allowing you to build APIs quickly.
By the end of this guide, you’ll know how to create a simple CRUD API.
What is an API?
An Application Programming Interface (API) allows two applications to communicate.
For example:
- A React website requests user data.
- A Spring Boot API processes the request.
- The API returns JSON.
- React displays the information.
React App
│
HTTP Request
│
▼
Spring Boot API
│
Business Logic
│
▼
Database
Step 1: Create a Spring Boot Project
Go to Spring Initializr and create a new project.
Choose:
- Project: Maven
- Language: Java
- Spring Boot: Latest Stable
- Packaging: Jar
Dependencies:
- Spring Web
- Spring Data JPA
- MySQL Driver (or PostgreSQL)
- Lombok (optional)
- Validation
Generate and open it in IntelliJ or VS Code.
Project Structure
src
└── main
├── java
│ └── com.example.demo
│ ├── controller
│ ├── service
│ ├── repository
│ ├── entity
│ └── DemoApplication.java
│
└── resources
└── application.properties
Each folder has a specific responsibility.
Step 2: Configure the Database
Example for MySQL:
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
Step 3: Create an Entity
Suppose we’re building a Student API.
package com.example.demo.entity;
import jakarta.persistence.*;
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// getters and setters
}
This class becomes a database table.
Step 4: Create the Repository
Repositories communicate with the database.
package com.example.demo.repository;
import com.example.demo.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
public interface StudentRepository
extends JpaRepository<Student, Long> {
}
Notice there is almost no code.
Spring automatically creates methods like:
- save()
- findAll()
- findById()
- deleteById()
Step 5: Create the Service
The service contains business logic.
package com.example.demo.service;
import com.example.demo.entity.Student;
import com.example.demo.repository.StudentRepository;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class StudentService {
private final StudentRepository repository;
public StudentService(StudentRepository repository) {
this.repository = repository;
}
public List<Student> getStudents() {
return repository.findAll();
}
public Student addStudent(Student student) {
return repository.save(student);
}
}
The service sits between the controller and repository.
Controller
│
▼
Service
│
▼
Repository
│
▼
Database
Step 6: Create the Controller
Controllers receive HTTP requests.
package com.example.demo.controller;
import com.example.demo.entity.Student;
import com.example.demo.service.StudentService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/students")
public class StudentController {
private final StudentService service;
public StudentController(StudentService service) {
this.service = service;
}
@GetMapping
public List<Student> getStudents() {
return service.getStudents();
}
@PostMapping
public Student createStudent(
@RequestBody Student student) {
return service.addStudent(student);
}
}
Now your API is live.
Understanding the Annotations
@RestController
Marks the class as a REST controller.
@RestController
public class StudentController
Instead of returning HTML, it returns JSON.
@RequestMapping
Defines the base URL.
@RequestMapping("/students")
All routes begin with:
/students
@GetMapping
Handles GET requests.
@GetMapping
Request:
GET /students
Returns:
[
{
"id":1,
"name":"John",
"email":"[email protected]"
}
]
@PostMapping
Handles POST requests.
@PostMapping
Request:
POST /students
Body:
{
"name":"Jane",
"email":"[email protected]"
}
@RequestBody
Converts incoming JSON into a Java object.
Incoming JSON:
{
"name":"Mike",
"email":"[email protected]"
}
Automatically becomes:
Student student
Testing the API
Use:
- Postman
- Insomnia
- Bruno
- VS Code REST Client
Example request:
GET http://localhost:8080/students
POST request:
POST http://localhost:8080/students
Body:
{
"name":"Sarah",
"email":"[email protected]"
}
Add Update API
Service:
public Student update(Long id, Student student){
Student existing = repository.findById(id)
.orElseThrow();
existing.setName(student.getName());
existing.setEmail(student.getEmail());
return repository.save(existing);
}
Controller:
@PutMapping("/{id}")
public Student updateStudent(
@PathVariable Long id,
@RequestBody Student student){
return service.update(id, student);
}
Request:
PUT /students/1
Body:
{
"name":"James",
"email":"[email protected]"
}
Delete API
Service:
public void delete(Long id){
repository.deleteById(id);
}
Controller:
@DeleteMapping("/{id}")
public void deleteStudent(
@PathVariable Long id){
service.delete(id);
}
Request:
DELETE /students/1
Get Single Student
Service:
public Student getStudent(Long id){
return repository.findById(id)
.orElseThrow();
}
Controller:
@GetMapping("/{id}")
public Student getStudent(
@PathVariable Long id){
return service.getStudent(id);
}
Request:
GET /students/1
Understanding HTTP Methods
| Method | Purpose | Example |
|---|---|---|
| GET | Retrieve data | Get all students |
| POST | Create data | Add student |
| PUT | Replace/update data | Update student |
| PATCH | Partially update data | Update only email |
| DELETE | Remove data | Delete student |
Common Annotations You’ll Use
| Annotation | Purpose |
|---|---|
| @RestController | Creates REST controller |
| @RequestMapping | Base route |
| @GetMapping | GET endpoint |
| @PostMapping | POST endpoint |
| @PutMapping | PUT endpoint |
| @DeleteMapping | DELETE endpoint |
| @RequestBody | Reads JSON body |
| @PathVariable | Reads URL parameter |
| @RequestParam | Reads query parameter |
| @Autowired | Injects dependencies (constructor injection is generally preferred) |
| @Service | Business logic |
| @Repository | Database layer |
| @Entity | Database table |
| @Id | Primary key |
| @GeneratedValue | Auto-generated ID |
Example API Flow
When a client requests GET /students:
Client
│
▼
GET /students
│
▼
StudentController
│
calls
▼
StudentService
│
calls
▼
StudentRepository
│
queries
▼
MySQL Database
│
returns data
▼
Repository
▼
Service
▼
Controller
▼
JSON Response
Best Practices
- Keep controllers thin; place business logic in services.
- Use constructor injection instead of field injection (
@Autowired) for better testability. - Validate input with
@Validand Jakarta Validation annotations like@NotBlankand@Email. - Return appropriate HTTP status codes (
200 OK,201 Created,204 No Content,400 Bad Request,404 Not Found). - Handle exceptions globally using
@ControllerAdvicefor consistent error responses. - Use DTOs (Data Transfer Objects) instead of exposing entity classes directly in larger applications.
- Document your API with Swagger/OpenAPI.
Typical Spring Boot API Architecture
HTTP Request
│
▼
StudentController
│
▼
StudentService
│
▼
StudentRepository
│
▼
MySQL Database
│
▼
JSON Response
This layered architecture keeps responsibilities separate: the Controller handles HTTP requests and responses, the Service contains business rules, the Repository manages database access, and the Entity maps Java objects to database tables. As your application grows, you can add DTOs, validation, security (Spring Security), and API documentation without changing this overall structure.

Latest tech news and coding tips.