Build Your First Spring Boot CRUD API
We will create a very small Student REST API. To keep the first backend lesson easy, almost everything will live inside one controller file.
StudentController.java,
store students in an ArrayList, and implement GET, POST, PUT, and DELETE APIs.
↓ HTTP Request
StudentController
↓ reads or changes
ArrayList<Student>
↓ returns Java object
Spring/Jackson converts it to JSON
↓ HTTP Response
No database, repository, service layer, DTO, or advanced architecture yet. First understand how an HTTP request reaches Java code.
Install the Required Tools
You only need Java, VS Code, and a few extensions.
Install
- JDK 17 or newer
- Visual Studio Code
- Extension Pack for Java
- Spring Boot Extension Pack
java -version
If the command prints a Java version, your JDK is available.
Generate the Spring Boot Project
Spring Initializr creates the starting Maven project for us.
- Open https://start.spring.io.
- Choose Maven.
- Choose Java.
- Select a stable Spring Boot version.
- Group:
com.example - Artifact:
studentapi - Name:
studentapi - Packaging: Jar
- Java: choose your installed version, for example 17 or 21.
- Add dependency: Spring Web.
- Click Generate.
It gives us the tools required to create REST endpoints such as @RestController,
@GetMapping, @PostMapping, and an embedded web server.
Open the Project
Extract the downloaded ZIP and open the project folder in VS Code.
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/com/example/studentapi/
│ │ │ └── StudentapiApplication.java
│ │ └── resources/
│ │ └── application.properties
│ └── test/
└── mvnw / mvnw.cmd
| File | Purpose |
|---|---|
pom.xml |
Maven project configuration and dependencies. |
StudentapiApplication.java |
Starts Spring Boot. |
application.properties |
Application configuration. |
Start Spring Boot Once
Before writing APIs, confirm that the generated project runs.
mvn spring-boot:run
The terminal should show that Tomcat started, normally on port 8080. Keep the
application running while testing endpoints.
Understand the Generated Main Class
Spring Initializr already created the class that starts our application.
package com.example.studentapi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StudentapiApplication {
public static void main(String[] args) {
SpringApplication.run(StudentapiApplication.class, args);
}
}
| Code | Meaning |
|---|---|
@SpringBootApplication |
Marks this as the main Spring Boot application and enables automatic configuration/component scanning. |
main() |
Normal Java program entry point. |
SpringApplication.run(...) |
Starts Spring, creates the application context, and starts the embedded server. |
Create Only One New Java File
Inside the same package, create StudentController.java. We are
deliberately not creating separate model, service, or repository files.
├── StudentapiApplication.java
└── StudentController.java
package com.example.studentapi;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/api/students")
public class StudentController {
}
| Code | Meaning |
|---|---|
@RestController |
Tells Spring that this class contains REST API endpoints. |
@RequestMapping("/api/students") |
Adds the same base URL to every endpoint in this controller. |
ResponseEntity |
Lets us control the HTTP response status and body. |
Put Student and ArrayList Inside the Controller
The controller will contain the Student class and our temporary in-memory data.
private final List<Student> students = new ArrayList<>();
private int nextId = 1;
public StudentController() {
students.add(new Student(nextId++, "Asha", 20, "CSE"));
students.add(new Student(nextId++, "Rahul", 21, "ECE"));
}
public static class Student {
private int id;
private String name;
private int age;
private String course;
public Student() {
}
public Student(int id, String name, int age, String course) {
this.id = id;
this.name = name;
this.age = age;
this.course = course;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getCourse() {
return course;
}
public void setCourse(String course) {
this.course = course;
}
}
Acts like our temporary database while the program is running.
Generates IDs because we do not have a database doing that for us.
When JSON arrives in a request body, Spring uses Jackson to create a Student object. A no-argument constructor plus setters makes that process simple for beginners.
GET All Students
Our first endpoint simply returns the complete ArrayList.
@GetMapping
public List<Student> getAllStudents() {
return students;
}
↓
@GetMapping method runs
↓
returns List<Student>
↓
Spring/Jackson converts Java objects to JSON
↓
200 OK
Open http://localhost:8080/api/students in the browser. You should receive a JSON
array.
GET One Student by ID
The value inside the URL becomes a Java method parameter using
@PathVariable.
@GetMapping("/{id}")
public ResponseEntity<Student> getStudentById(@PathVariable int id) {
for (Student student : students) {
if (student.getId() == id) {
return ResponseEntity.ok(student);
}
}
return ResponseEntity.notFound().build();
}
| Part | Meaning |
|---|---|
/{id} |
Creates a variable section in the URL. |
@PathVariable int id |
Reads that URL value into Java. |
ResponseEntity.ok(student) |
Returns 200 OK with the Student as JSON. |
notFound() |
Returns 404 when no matching student exists. |
POST a New Student
The client sends JSON. @RequestBody asks Spring to convert that
JSON into a Student object.
@PostMapping
public ResponseEntity<Student> createStudent(@RequestBody Student student) {
student.setId(nextId++);
students.add(student);
return ResponseEntity.status(201).body(student);
}
Example request body
{
"name": "Neha",
"age": 22,
"course": "IT"
}
↓ @RequestBody
Student object
↓ set generated ID
↓ students.add(student)
↓ 201 Created + Student JSON
Which HTTP method are we using to create a student?
PUT to Update a Student
We find the existing student by ID, then copy the new values from the request body.
@PutMapping("/{id}")
public ResponseEntity<Student> updateStudent(
@PathVariable int id,
@RequestBody Student updatedStudent) {
for (Student student : students) {
if (student.getId() == id) {
student.setName(updatedStudent.getName());
student.setAge(updatedStudent.getAge());
student.setCourse(updatedStudent.getCourse());
return ResponseEntity.ok(student);
}
}
return ResponseEntity.notFound().build();
}
Example request
PUT /api/students/1
{
"name": "Asha Sharma",
"age": 21,
"course": "AI & ML"
}
The ID comes from the URL and identifies which existing student we are editing. We only update the editable fields.
DELETE a Student
Use the ID in the URL and remove the matching item from the ArrayList.
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteStudent(@PathVariable int id) {
for (Student student : students) {
if (student.getId() == id) {
students.remove(student);
return ResponseEntity.noContent().build();
}
}
return ResponseEntity.notFound().build();
}
↓ @PathVariable
find matching student
↓ remove from ArrayList
↓
204 No Content
If not found → 404 Not Found
We return no response body after a successful delete, so 204 No Content is
appropriate.
Complete StudentController.java
At this point your entire CRUD backend, apart from the generated Spring Boot main class, is in this one file.
package com.example.studentapi;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/api/students")
public class StudentController {
private final List<Student> students = new ArrayList<>();
private int nextId = 1;
public StudentController() {
students.add(new Student(nextId++, "Asha", 20, "CSE"));
students.add(new Student(nextId++, "Rahul", 21, "ECE"));
}
@GetMapping
public List<Student> getAllStudents() {
return students;
}
@GetMapping("/{id}")
public ResponseEntity<Student> getStudentById(@PathVariable int id) {
for (Student student : students) {
if (student.getId() == id) {
return ResponseEntity.ok(student);
}
}
return ResponseEntity.notFound().build();
}
@PostMapping
public ResponseEntity<Student> createStudent(@RequestBody Student student) {
student.setId(nextId++);
students.add(student);
return ResponseEntity.status(201).body(student);
}
@PutMapping("/{id}")
public ResponseEntity<Student> updateStudent(
@PathVariable int id,
@RequestBody Student updatedStudent) {
for (Student student : students) {
if (student.getId() == id) {
student.setName(updatedStudent.getName());
student.setAge(updatedStudent.getAge());
student.setCourse(updatedStudent.getCourse());
return ResponseEntity.ok(student);
}
}
return ResponseEntity.notFound().build();
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteStudent(@PathVariable int id) {
for (Student student : students) {
if (student.getId() == id) {
students.remove(student);
return ResponseEntity.noContent().build();
}
}
return ResponseEntity.notFound().build();
}
public static class Student {
private int id;
private String name;
private int age;
private String course;
public Student() {
}
public Student(int id, String name, int age, String course) {
this.id = id;
this.name = name;
this.age = age;
this.course = course;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getCourse() {
return course;
}
public void setCourse(String course) {
this.course = course;
}
}
}
Test All CRUD Endpoints
You can use Postman, Thunder Client, REST Client, curl, or your Flutter app.
| Operation | Method | URL |
|---|---|---|
| Get all | GET | /api/students |
| Get one | GET | /api/students/1 |
| Create | POST | /api/students |
| Update | PUT | /api/students/1 |
| Delete | DELETE | /api/students/1 |
curl http://localhost:8080/api/students
curl -X POST http://localhost:8080/api/students \
-H "Content-Type: application/json" \
-d '{"name":"Neha","age":22,"course":"IT"}'
Understand One Request End-to-End
Follow what happens when the client creates a student.
↓
2. Spring matches @PostMapping
↓
3. Jackson converts JSON → Student object
↓
4. createStudent() runs inside StudentController
↓
5. Controller generates an ID
↓
6. Controller adds Student to ArrayList
↓
7. ResponseEntity creates 201 Created
↓
8. Jackson converts Student → JSON
↓
9. Client receives status + JSON
The data lives only in RAM. Stop and restart the Spring Boot application and your newly created students disappear.
Student CRUD API Revision
Review the ideas before connecting this backend to Flutter.
ArrayList<Student> declared directly in
StudentController.
Completion checklist
- I can create a Spring Boot project from start.spring.io.
- I can run Spring Boot from VS Code.
- I understand the generated main class.
- I can create a REST controller.
- I can temporarily store objects in an ArrayList.
- I can create GET, POST, PUT, and DELETE endpoints.
- I understand @PathVariable.
- I understand @RequestBody.
- I can return 200, 201, 204, and 404 responses.
- I understand that this version has no persistence.
Practice
- Add an
emailfield to Student. - Add a third seed student.
- Create
GET /api/students/course/{course}. - Prevent creating a student when the name is empty.
- Connect these endpoints to your Flutter networking app.
First Spring Boot backend complete! 🎉
You now understand CRUD without hiding the logic behind multiple layers. Once this flow is comfortable, you can introduce separate model/service/repository files and a real database.