Creating a Spring Boot Project and a First Endpoint

First lesson of the Spring Boot: REST API course, free to read: about 18 minutes, 3 exercises and 3 quiz questions. This is the catalogue's base lesson; in the student space, it is rewritten for your profile.

Objectives

  • Generate a Spring Boot project with Spring Initializr and understand its structure
  • Write a REST controller that returns JSON
  • Start the application and call the endpoint with curl

Spring Boot@RestControllerJSON serialization with Jackson

Spring Boot is the most widely used framework for building web APIs in Java. It builds on the Spring Framework and brings two essential things: auto-configuration (it guesses the configuration from the dependencies present) and an embedded web server (Tomcat by default). The result: an API starts with a simple main, with no server to install.

This course uses Spring Boot 4.1 (Spring Framework 7) with Java 25, the current LTS version of Java.

Generating the project

The official Spring Initializr site (start.spring.io), also built into IntelliJ IDEA and VS Code, generates the skeleton. It defaults to Gradle and Java 17: choose Maven, Java 25, a group (fr.boutique), and the Spring Web dependency. From the command line:

curl https://start.spring.io/starter.zip -d type=maven-project -d dependencies=web -d javaVersion=25 \
     -d groupId=fr.boutique -d artifactId=boutique -d packageName=fr.boutique -d baseDir=boutique -o boutique.zip
unzip boutique.zip

Resulting structure:

boutique/
├── pom.xml                       # dependencies (spring-boot-starter-webmvc...)
├── mvnw                          # Maven Wrapper: no need to install Maven
└── src/
    ├── main/java/fr/boutique/BoutiqueApplication.java
    ├── main/resources/application.properties
    └── test/java/fr/boutique/BoutiqueApplicationTests.java

Starters (spring-boot-starter-webmvc, -validation, -data-jpa…) group together consistent dependencies whose versions Spring Boot manages. The “Spring Web” dependency corresponds to the spring-boot-starter-webmvc starter (new name since Spring Boot 4); Spring Initializr also adds its test starter, spring-boot-starter-webmvc-test, because each module now has its own.

The main class

package fr.boutique;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication // auto-configuration + component scan of fr.boutique.*
public class BoutiqueApplication {
    public static void main(String[] args) {
        SpringApplication.run(BoutiqueApplication.class, args);
    }
}

Spring scans the package of this class and its subpackages: put your controllers in fr.boutique.produit, for example, never in a “sibling” package.

A first REST controller

package fr.boutique.produit;

import org.springframework.web.bind.annotation.*;
import java.util.List;

record ProduitDto(long id, String nom, double prix) {}

@RestController                 // returned values become the response body
@RequestMapping("/api")         // common prefix for the class's routes
class BonjourController {

    @GetMapping("/bonjour")     // GET /api/bonjour
    String bonjour() {
        return "Hello from Spring Boot";
    }

    @GetMapping("/produits")    // GET /api/produits
    List<ProduitDto> produits() {
        return List.of(new ProduitDto(1, "Clavier", 45.5),
                       new ProduitDto(2, "Écran", 180));
    }
}

@RestController combines @Controller and @ResponseBody. The Jackson library, included in the webmvc starter (Jackson 3 since Spring Boot 4, tools.jackson.* packages), automatically converts the record to JSON: [{"id":1,"nom":"Clavier","prix":45.5}, ...]. Records are perfect for this: immutable, concise, serialized with no configuration.

Running and testing

./mvnw spring-boot:run                 # starts on port 8080
curl http://localhost:8080/api/produits

To change the port, add to application.properties:

server.port=8081
spring.application.name=boutique

The startup logs show Tomcat started on port 8081. If the port is already in use, the application refuses to start: stop the old instance or change the port.

Key takeaways

  • Spring Boot = Spring + auto-configuration + embedded server.
  • A @RestController method annotated with @GetMapping becomes an endpoint.
  • Returned objects are serialized to JSON by Jackson.

Exercises

Solutions and tests stay on the server. In the student space, your code is run and checked, and the tutor gives hints before the solution.

  1. TaskDifficulty 12 hints

    Generate and run your first API

    In your working environment, generate a Spring Boot 4 project (Maven, Java 25, Spring Web dependency), for example with curl https://start.spring.io/starter.zip -d type=maven-project -d dependencies=web -d javaVersion=25 -d groupId=fr.boutique -d artifactId=boutique -d packageName=fr.boutique -d baseDir=boutique -o boutique.zip then unzip boutique.zip && cd boutique (without type=maven-project, Spring Initializr generates a Gradle project, with no pom.xml or mvnw). Create a @RestController exposing GET /api/bonjour, which returns a Message(String texte) record, and GET /api/produits, which returns a list of three products. Start the application with ./mvnw spring-boot:run and call both endpoints with curl.

    • The application starts and the logs show "Tomcat started on port 8080"
    • curl http://localhost:8080/api/bonjour returns a JSON object {"texte": ...}
    • curl http://localhost:8080/api/produits returns a JSON array of three products
    • The controller is in a subpackage of the @SpringBootApplication class
  2. CodeDifficulty 2Server sandbox2 hints

    Serialize a record to JSON like Jackson

    To understand what Jackson does, write static String toJson(Produit p) for the record Produit(long id, String nom, double prix, boolean disponible). The format is compact, in component order:

    {"id":1,"nom":"Clavier","prix":45.5,"disponible":true}

    Strings are enclosed in quotes and the \ and " characters they contain are escaped (preceded by a \). Each input line is id;nom;prix;disponible; print the JSON of each product.

    import java.util.*;
    
    public class Main {
        static String echapper(String s) {
            // TODO : échapper \ puis "
            return s;
        }
    
        static String toJson(Produit p) {
            // TODO
            return "";
        }
    
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            while (sc.hasNextLine()) {
                String l = sc.nextLine();
                if (l.isBlank()) continue;
                String[] c = l.split(";");
                Produit p = new Produit(Long.parseLong(c[0]), c[1], Double.parseDouble(c[2]), Boolean.parseBoolean(c[3]));
                System.out.println(toJson(p));
            }
        }
    }
    
    record Produit(long id, String nom, double prix, boolean disponible) {}
  3. Multiple choiceDifficulty 11 hint

    @RestController

    What is the difference between @RestController and @Controller?

    • @RestController adds @ResponseBody: the returned value is written to the response body (JSON)
    • @RestController only accepts GET requests
    • There is no difference

End-of-lesson quiz

  1. Which web server does Spring Boot embed by default with the Spring Web starter?

    • Apache HTTPD
    • Tomcat
    • Nginx
  2. Which file contains the application configuration (port, name…)?

    • pom.xml
    • src/main/resources/application.properties
    • BoutiqueApplication.java
  3. Which library converts Java objects to JSON in a Spring Boot web application?

    • Jackson
    • Hibernate
    • JUnit

The rest of the course

  1. Routes, HTTP Verbs, and ResponseEntity20 min
  2. DTOs and Data Validation20 min
  3. Service Layer and Dependency Injection20 min
  4. Global Error Handling and API Testing22 min

Spring Boot: REST API · Advanced · 2 h 40 min