Java Spring Boot Backend

How to Build a REST API with Spring Boot in 30 Minutes

If you know basic Java, you can build a REST API with Spring Boot in 30 minutes. In this guide, we will create a small Task API with endpoints to list, create, update, and delete tasks. We will keep the project simple: no database, no security, and no heavy architecture. The goal is to understand the moving parts first, then you can replace the in-memory storage with a real database later.

What you will build: a working JSON API at /api/tasks using Spring Boot, Spring Web, Java records, and standard HTTP methods.

Prerequisites

Before starting, make sure you have Java installed and an editor ready. Java 17 or newer is recommended for modern Spring Boot projects. You should also have a terminal available so you can run the app and test the endpoints with curl.

  • Java 17 or newer
  • IntelliJ IDEA, VS Code, or another Java editor
  • Maven wrapper from the generated Spring Boot project
  • Basic knowledge of classes, methods, and HTTP requests

Minute 0-5: Create the Spring Boot Project

Open Spring Initializr and create a project with these options:

  • Project: Maven
  • Language: Java
  • Spring Boot: latest stable version
  • Java: 17 or newer
  • Dependency: Spring Web

Download the project, unzip it, and open it in your editor. The important dependency is spring-boot-starter-web, which gives you Spring MVC, JSON support, and an embedded Tomcat server.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Minute 5-8: Understand the Project Structure

A fresh Spring Boot project looks small because most configuration is automatic. For this tutorial, we will add three files inside the main package.

src/
├── main/
│   ├── java/com/example/demo/
│   │   ├── DemoApplication.java
│   │   ├── Task.java
│   │   └── TaskController.java
│   └── resources/
│       └── application.properties
└── test/

Keep new Java files in the same package as DemoApplication.java or in a child package. That lets Spring Boot discover your controller automatically.

Minute 8-12: Create the Task Model

Create a file named Task.java. A Java record is perfect for a simple API response because it is concise, immutable, and automatically serialised to JSON by Spring Boot.

package com.example.demo;

public record Task(
    Long id,
    String title,
    boolean completed
) {}

When a controller returns a Task, Spring Boot converts it into JSON like this:

{
  "id": 1,
  "title": "Learn Spring Boot",
  "completed": false
}

Minute 12-22: Build the REST Controller

Now create TaskController.java. This controller stores tasks in a Map so you can focus on REST API design without setting up a database.

package com.example.demo;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

@RestController
@RequestMapping("/api/tasks")
public class TaskController {

    private final Map<Long, Task> tasks = new LinkedHashMap<>();
    private final AtomicLong nextId = new AtomicLong(1);

    @GetMapping
    public List<Task> getAllTasks() {
        return new ArrayList<>(tasks.values());
    }

    @GetMapping("/{id}")
    public Task getTaskById(@PathVariable Long id) {
        Task task = tasks.get(id);

        if (task == null) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Task not found");
        }

        return task;
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Task createTask(@RequestBody CreateTaskRequest request) {
        Long id = nextId.getAndIncrement();
        Task task = new Task(id, request.title(), false);
        tasks.put(id, task);
        return task;
    }

    @PutMapping("/{id}")
    public Task updateTask(@PathVariable Long id, @RequestBody UpdateTaskRequest request) {
        if (!tasks.containsKey(id)) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Task not found");
        }

        Task updatedTask = new Task(id, request.title(), request.completed());
        tasks.put(id, updatedTask);
        return updatedTask;
    }

    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteTask(@PathVariable Long id) {
        if (tasks.remove(id) == null) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Task not found");
        }
    }

    public record CreateTaskRequest(String title) {}

    public record UpdateTaskRequest(String title, boolean completed) {}
}

What the Annotations Mean

The code above may look compact, but it covers the core Spring Boot REST API concepts:

  • @RestController tells Spring this class returns API responses, not HTML views.
  • @RequestMapping("/api/tasks") sets the base URL for every method.
  • @GetMapping, @PostMapping, @PutMapping, and @DeleteMapping map HTTP methods to Java methods.
  • @PathVariable reads values from the URL, such as /api/tasks/1.
  • @RequestBody converts incoming JSON into a Java record.
  • @ResponseStatus controls the HTTP status code returned by the endpoint.

Minute 22-25: Run the Application

Start the API from the project root. The Maven wrapper means you do not need Maven installed globally.

./mvnw spring-boot:run

On Windows, use:

mvnw.cmd spring-boot:run

When the logs say Tomcat started on port 8080, your REST API is live at http://localhost:8080.

Minute 25-30: Test the REST API

Use curl or Postman to test each endpoint. First, create a task:

curl -X POST http://localhost:8080/api/tasks \
  -H "Content-Type: application/json" \
  -d '{"title":"Build my first Spring Boot API"}'

You should get a response like this:

{
  "id": 1,
  "title": "Build my first Spring Boot API",
  "completed": false
}

List all tasks:

curl http://localhost:8080/api/tasks

Get one task by ID:

curl http://localhost:8080/api/tasks/1

Update a task:

curl -X PUT http://localhost:8080/api/tasks/1 \
  -H "Content-Type: application/json" \
  -d '{"title":"Finish the REST API","completed":true}'

Delete a task:

curl -X DELETE http://localhost:8080/api/tasks/1

REST API Endpoint Summary

Your Spring Boot REST API now supports the standard CRUD workflow:

  • GET /api/tasks - list all tasks
  • GET /api/tasks/{id} - fetch one task
  • POST /api/tasks - create a new task
  • PUT /api/tasks/{id} - update an existing task
  • DELETE /api/tasks/{id} - delete a task

Common Beginner Mistakes

  • Putting the controller outside the package scanned by @SpringBootApplication.
  • Forgetting @RequestBody on methods that accept JSON.
  • Using GET for operations that create, update, or delete data.
  • Expecting in-memory data to survive after restarting the application.
  • Forgetting the Content-Type: application/json header during POST and PUT requests.

Key Takeaways

  • Spring Boot can expose REST endpoints with very little setup.
  • spring-boot-starter-web gives you controllers, JSON support, and an embedded server.
  • Java records are a clean way to model request and response data.
  • Use the correct HTTP method for each action: GET, POST, PUT, and DELETE.
  • An in-memory API is great for learning, but production apps should use a real database.

What's Next?

You now have a working REST API with Spring Boot in about 30 minutes. The next step is to replace the Map with a database using Spring Data JPA, add validation with spring-boot-starter-validation, and secure endpoints with Spring Security. Once you understand controllers and JSON flow, those upgrades become much easier.

If you want a more production-focused version, read the Spring Boot REST API Java 21 production setup guide next.

Dhiraj Roy
Dhiraj Roy

Backend developer & tech writer. Writing about Java, Spring Boot, Python, and AI at Digital Drift.