CodeGym /Courses /Module 5. Spring /Hands-on: building a REST controller in Spring MVC

Hands-on: building a REST controller in Spring MVC

Module 5. Spring
Level 7 , Lesson 5
Available

In previous lectures we covered the basics of Spring MVC: the architecture, key annotations, and routing fundamentals. Now it's time to put that knowledge into practice and build a full REST API.

Let's build a controller to manage books in a library. Our API will be able to get a list of books, find a book by ID, add new books, update their information, and delete them from the store. Along the way we'll implement all the necessary CRUD operations, handle HTTP methods (GET, POST, PUT, DELETE), return data as JSON, and add basic testing.

A REST API is the backbone of modern web development. Whether you're building a web app, a mobile app, or a microservices architecture, you'll be creating and maintaining API endpoints. Let's learn how to do it right!


1. Project setup

Dependencies. First, let's make sure our Spring Boot project is configured correctly. Include the necessary dependencies in pom.xml:


<dependencies>
  <!-- Spring Web for MVC -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <!-- Dependency for JSON handling -->
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
  </dependency>
</dependencies>

Alright, now let's move on to creating the controller.


2. Description of the Book entity

Before implementing the controller, we need the entity it will work with. Let's create a simple Book class.


package com.example.demo.model;

public class Book {

    private Long id;
    private String title;
    private String author;

    // Constructors
    public Book() {}

    public Book(Long id, String title, String author) {
        this.id = id;
        this.title = title;
        this.author = author;
    }

    // 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;
    }
}

3. Creating the REST controller

Now we're ready to create our controller. It will handle HTTP requests to manage books. Use the @RestController annotation to tell Spring that this class handles REST requests.


package com.example.demo.controller;

import com.example.demo.model.Book;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/books")
public class BookController {

    private final List<Book> books = new ArrayList<>();

    // Data initialization
    public BookController() {
        books.add(new Book(1L, "Clean Code", "Robert C. Martin"));
        books.add(new Book(2L, "Effective Java", "Joshua Bloch"));
    }

    // Get all books
    @GetMapping
    public List<Book> getAllBooks() {
        return books;
    }

    // Get a book by ID
    @GetMapping("/{id}")
    public Book getBookById(@PathVariable Long id) {
        return books.stream()
                .filter(book -> book.getId().equals(id))
                .findFirst()
                .orElseThrow(() -> new RuntimeException("Book not found"));
    }

    // Create a new book
    @PostMapping
    public Book createBook(@RequestBody Book book) {
        books.add(book);
        return book;
    }

    // Update a book
    @PutMapping("/{id}")
    public Book updateBook(@PathVariable Long id, @RequestBody Book updatedBook) {
        Book book = getBookById(id);
        book.setTitle(updatedBook.getTitle());
        book.setAuthor(updatedBook.getAuthor());
        return book;
    }

    // Delete a book
    @DeleteMapping("/{id}")
    public void deleteBook(@PathVariable Long id) {
        Book book = getBookById(id);
        books.remove(book);
    }
}

4. Controller code breakdown

Main controller methods

  • GET /books Returns the list of all books. Super simple — it just returns the books list.
  • GET /books/{id} Finds a book by ID. If the book isn't found, an exception is thrown (you can improve error handling later).
  • POST /books Creates a new book. We pass a Book object in the request body (the @RequestBody annotation).
  • PUT /books/{id} Updates an existing book by ID. Here we first find the book by ID and then update its data.
  • DELETE /books/{id} Deletes a book by ID. We find the book first, then remove it from the list.

Annotation details

  • @RequestMapping("/books"): base path for all requests.
  • @GetMapping, @PostMapping, @PutMapping, @DeleteMapping: handle HTTP requests.
  • @PathVariable extracts parameters from the request path.
  • @RequestBody reads the request body and converts it into a Java object.

5. Testing the controller

You can test the API using tools like Postman or plain cURL. Example requests:

GET all books


GET http://localhost:8080/books

GET book by ID


GET http://localhost:8080/books

POST a new book


POST http://localhost:8080/books
Content-Type: application/json

{
    "id": 3,
    "title": "The Pragmatic Programmer",
    "author": "Andrew Hunt"
}

DELETE a book


DELETE http://localhost:8080/books/1

6. Common mistakes and how to fix them

  1. 404 Not Found on GET /books/{id} This happens if the requested book isn't in the list. Make sure books is initialized properly.
  2. JSON serialization error Check that all object fields have getters/setters, otherwise Jackson won't be able to serialize the object to JSON.
  3. 415 Unsupported Media Type on POST or PUT Make sure the request header includes Content-Type: application/json.

Now we have a fully functional REST controller! In the next lecture we'll get into the Thymeleaf templating engine so you can learn how to build nice HTML pages for our web apps.

Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION