Build a Bookstore REST API

Build a CRUD REST API for a bookstore using Spring Boot and Java.

Introduction

30 Second Summary

Every time you open an app on your phone, it talks to a server behind the scenes. That server is a REST API, and it's the backbone of every modern application.

In this project, you will build a Bookstore REST API using Spring Boot that handles creating, reading, updating, and deleting books through HTTP requests.

What You'll Build

A fully functional REST API running on your local machine that responds to HTTP requests with JSON data.

By the end of this project, you'll have:

  • A Spring Boot project with proper Maven structure generated from Spring Initializr.
  • A Book model class and a REST controller with five endpoints covering all CRUD operations.
  • Hands-on experience testing your API with PowerShell commands to verify each endpoint works correctly.
  • Secret Mission: Add a search endpoint that lets you filter books by author or title.

Are there any prerequisites?

You should have basic Java knowledge including classes, methods, and lists. No prior experience with Spring Boot or REST APIs is needed.

Generate Your Spring Boot Project

Every Spring Boot project starts from a template that wires up build files, folder structure, and dependencies for you. Without this template, you would need to create dozens of configuration files by hand.

Spring Initializr is a web tool that generates a ready-to-run project in seconds. In this step, you will use it to create your project, open it in VS Code, and confirm the server starts successfully.

In this step, get ready to:
  • Generate a Spring Boot project using Spring Initializr.
  • Open the project in VS Code.
  • Verify the server starts and responds to requests.
Use Spring Initializr to create the project

Spring Initializr is a website that lets you pick your project settings and downloads a ZIP file with everything configured. You will use it to generate a Maven project with a single dependency.

  • Open your browser and go to https://start.spring.io.
  • Under **Project**, select Maven.
  • Under Language, select Java.
  • Under Spring Boot, select 4.0.6 (or the latest stable version shown).
  • In the Project Metadata section, set Group to com.example.
  • Set Artifact to bookstore.
  • Set Name to bookstore.
  • Set Package name to com.example.bookstore.
  • Set Packaging to Jar.
  • Set Java to 17.
  • Click the ADD DEPENDENCIES button near the top right.
  • Search for Spring Web and select it from the dropdown.
  • Click Generate to download the ZIP file.

What is Spring Initializr doing?

Spring Initializr creates a complete project folder with a pom.xml build file, a main application class, and the Maven Wrapper (mvnw.cmd).

The Maven Wrapper lets you run Maven commands without installing Maven separately. It downloads the correct Maven version automatically the first time you use it.

Why Maven over Gradle?

Maven is the most common build tool in enterprise Java shops. Most Spring Boot tutorials and job postings reference Maven, making it the better choice for building transferable skills.

Extract and open in VS Code
  • Find the downloaded bookstore.zip file in your Downloads folder.
  • Right-click the ZIP file and select Extract All (Windows) or double-click to unzip (macOS).
  • Extract it to your Desktop so you can find it easily.

Now open the extracted project folder in VS Code.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type VS Code and press Enter to open it.
  • In VS Code, click File in the top menu bar.
  • Click Open Folder.
  • Navigate to your Desktop and select the bookstore folder, then click Select Folder.

You should see a file tree in the left sidebar with folders like src and files like pom.xml.

VS Code asking you to trust the folder?

VS Code may show a prompt asking if you trust the authors of this folder. Click Yes, I trust the authors to continue.

If VS Code shows notifications about Java extensions loading or indexing, let them finish before moving on. Help me with VS Code trust or Java extension issues.

Verify the project runs

Before writing any code, confirm that the generated project starts successfully. This proves your environment is configured correctly.

  • Open a terminal in VS Code by clicking Terminal in the top menu bar, then New Terminal.
  • Start the Spring Boot server by running this command:
.\mvnw.cmd spring-boot:run

What does this command do?

.\mvnw.cmd calls the Maven Wrapper bundled with your project. The spring-boot:run goal compiles your code and starts the embedded web server.

The first time you run this, Maven downloads all required dependencies. This may take a minute or two depending on your internet speed.

  • Wait for the terminal output to show Started BookstoreApplication.
  • Open your browser and go to http://localhost:8080.

You should see a page titled "Whitelabel Error Page" with a 404 status. This is expected. It means the server is running but you have not created any endpoints yet.

  • Return to your VS Code terminal and press Ctrl+C to stop the server.

Don't see Started BookstoreApplication?

If Maven fails to download dependencies, check your internet connection and try running the command again.

If you see an error about port 8080 already being in use, another application is occupying that port. Close any other servers or apps that might be using port 8080, then try again.

Help me troubleshoot my Spring Boot server not starting.

✔️ Awesome, I've got everything!

Great. Your project is generated and the server runs successfully. You are ready to start building your API.

ⓧ I'd like to double check the full code

Here is what your pom.xml should look like. This file was generated by Spring Initializr.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>4.0.6</version>
		<relativePath/>
	</parent>
	<groupId>com.example</groupId>
	<artifactId>bookstore</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>bookstore</name>
	<description>Bookstore REST API</description>
	<properties>
		<java.version>17</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webmvc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

And here is your main application class:

package com.example.bookstore;

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

@SpringBootApplication
public class BookstoreApplication {

	public static void main(String[] args) {
		SpringApplication.run(BookstoreApplication.class, args);
	}

}

Small differences are okay

Your generated pom.xml may have a slightly different description field (e.g. "Demo project for Spring Boot"). This does not affect functionality.

The important parts are the spring-boot-starter-webmvc dependency and the spring-boot-maven-plugin in the build section.

Your project is scaffolded and proven to run. Next up, you will create the Book model class that defines what a book looks like in your API.

Create the Book Model

Your Spring Boot server is up and running. Now it's time to define the data your API will manage.

Every REST API needs a data model. A model class defines the shape of the information your API stores and sends back to clients. In this step, you'll create a Book class that represents a single book in your store.

In this step, get ready to:
  • Create the Book.java model file.
  • Define the book's data fields, constructors, and accessor methods.
Create the Book.java file

The Book class lives in the same package as your main application file. This keeps things simple for now.

  • In VS Code, open the **Explorer** sidebar on the left.
  • Navigate to src/main/java/com/example/bookstore/.
  • Right-click the bookstore folder and select New File.
  • Name the file Book.java.

Why this folder?

Spring Boot uses a package-based structure. Your BookstoreApplication.java already lives in com.example.bookstore. Placing Book.java in the same package means Spring can automatically discover and use it without any extra configuration.

Add the Book class code

This class is a plain Java object (often called a POJO) that holds four pieces of information about a book: its ID, title, author, and price.

  • Copy the following code into your empty Book.java file:
package com.example.bookstore;

public class Book {

    // Fields that represent a book's data
    private Long id;
    private String title;
    private String author;
    private double price;

    // No-argument constructor (required for JSON deserialization)
    public Book() {
    }

    // Constructor with all fields for convenience
    public Book(Long id, String title, String author, double price) {
        this.id = id;
        this.title = title;
        this.author = author;
        this.price = price;
    }

    // Getters and setters for each field
    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;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

}

What does this code do?

The four private fields (id, title, author, price) define what data each book holds. They're private so that other classes must go through the getters and setters to access them.

The no-argument constructor Book() is required because Spring Boot uses it behind the scenes to create a Book object from incoming JSON data. Without it, your API would fail when receiving requests.

The getters and setters let Spring read each field when converting a Book to JSON (for responses) and write each field when converting JSON to a Book (for requests).

  • Save Book.java.
  • Confirm you can see Book.java listed in the Explorer sidebar at src/main/java/com/example/bookstore/, right next to BookstoreApplication.java.

Seeing a red squiggly underline?

If VS Code highlights errors in your file, make sure the package line at the top reads exactly package com.example.bookstore;. A mismatch between the file's location and its package declaration causes compile errors.

Also check that the file is named Book.java with a capital B. Java requires the filename to match the class name exactly.

Help me fix a red underline error in my Book.java file

✔️ Awesome, I've got everything!

Great. Double check you've saved Book.java before moving on.

ⓧ I'd like to double check the full code

Here's the complete Book.java file for comparison:

package com.example.bookstore;

public class Book {

    private Long id;
    private String title;
    private String author;
    private double price;

    public Book() {
    }

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

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

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

}

Your data model is ready. Next up, you'll build the REST controller that uses this Book class to handle HTTP requests for creating, reading, updating, and deleting books.

Create the REST Controller

Your Book model defines what a book looks like in your system. Now you need to build the part that actually listens for HTTP requests and responds with data.

In Spring Boot, a controller is the class that maps URLs to Java methods. Each method handles a specific type of request (GET, POST, PUT, DELETE) and returns data back to the caller as JSON.

In this step, get ready to:
  • Create the BookController.java file.
  • Set up the controller class with in-memory storage.
  • Add five CRUD endpoint methods for creating, reading, updating, and deleting books.
Create the BookController.java file

The controller lives in the same package as your Book model so Spring can find both classes automatically.

  • In the VS Code **Explorer** sidebar, navigate to src/main/java/com/example/bookstore/.
  • Right-click the bookstore folder and select New File.
  • Name the file BookController.java and press Enter.

The file opens in the editor, ready for code.

Set up the controller class with in-memory storage

Before adding endpoints, you need the class shell. This includes the annotations that tell Spring this class handles web requests, and the data structures that store books in memory.

  • Add the following code to BookController.java:
package com.example.bookstore;

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

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

// Tells Spring this class handles HTTP requests and returns JSON
@RestController
// All endpoints in this class start with /api/books
@RequestMapping("/api/books")
public class BookController {

    // In-memory list to store books (no database needed)
    private final List<Book> books = new ArrayList<>();
    // Thread-safe counter to generate unique IDs for each book
    private final AtomicLong counter = new AtomicLong();

}

What does this code do?

@RestController combines two Spring annotations: @Controller (marks the class as a request handler) and @ResponseBody (automatically converts return values to JSON).

@RequestMapping("/api/books") sets the base URL path for every endpoint in this class. Every method you add will be reachable under /api/books.

The ArrayList acts as a simple in-memory database. The AtomicLong safely increments an ID counter so each new book gets a unique number.

  • Save BookController.java.
  • Confirm VS Code shows no red squiggly underlines in the file. The imports should all resolve without errors.

Seeing red underlines on the imports?

Make sure the file is saved inside src/main/java/com/example/bookstore/. If it is in the wrong folder, the package declaration won't match the directory structure.

Check that the first line says package com.example.bookstore; exactly. A mismatch between the package name and folder path causes import errors.

Help me fix red underlines in my BookController imports.

Add the GET endpoint methods

GET requests are how clients retrieve data. You need two: one to list all books, and one to fetch a single book by its ID.

  • Inside the BookController class (below the counter field), add these two methods:
    // GET /api/books - returns every book in the list
    @GetMapping
    public List<Book> getAllBooks() {
        return books;
    }

    // GET /api/books/{id} - returns one book, or 404 if not found
    @GetMapping("/{id}")
    public ResponseEntity<Book> getBookById(@PathVariable Long id) {
        return books.stream()
                .filter(book -> book.getId().equals(id))
                .findFirst()
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }

What does this code do?

  • @GetMapping with no path maps to the base URL /api/books. It returns the full list, which Spring converts to a JSON array.
  • @GetMapping("/{id}") maps to URLs like /api/books/1. The @PathVariable annotation pulls the id value from the URL path.
  • ResponseEntity lets you control the HTTP status code. If the book is found, you return 200 OK. If not, you return 404 Not Found.
  • Save BookController.java.
  • You won't see a change yet. You'll test these endpoints in the next step once the server is running.
Add the POST, PUT, and DELETE endpoint methods

These three methods handle writing data. POST creates a new book, PUT updates an existing one, and DELETE removes one.

  • Below the getBookById method, add these three methods:
    // POST /api/books - creates a new book and returns it with 201 status
    @PostMapping
    public ResponseEntity<Book> createBook(@RequestBody Book book) {
        book.setId(counter.incrementAndGet());
        books.add(book);
        return ResponseEntity.status(HttpStatus.CREATED).body(book);
    }

    // PUT /api/books/{id} - updates an existing book, or 404 if not found
    @PutMapping("/{id}")
    public ResponseEntity<Book> updateBook(@PathVariable Long id, @RequestBody Book book) {
        for (int i = 0; i < books.size(); i++) {
            if (books.get(i).getId().equals(id)) {
                book.setId(id);
                books.set(i, book);
                return ResponseEntity.ok(book);
            }
        }
        return ResponseEntity.notFound().build();
    }

    // DELETE /api/books/{id} - removes a book, 204 on success or 404 if not found
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteBook(@PathVariable Long id) {
        boolean removed = books.removeIf(book -> book.getId().equals(id));
        if (removed) {
            return ResponseEntity.noContent().build();
        }
        return ResponseEntity.notFound().build();
    }

What does this code do?

  • @RequestBody tells Spring to parse the incoming JSON body into a Book object. This is how the API receives data from clients.
  • createBook assigns a unique ID using counter.incrementAndGet(), adds the book to the list, and returns HTTP 201 Created.
  • updateBook loops through the list to find the book by ID, replaces it, and returns the updated book. If the ID doesn't exist, it returns 404.
  • deleteBook uses removeIf to find and remove the matching book. It returns 204 No Content on success (the response body is empty because the book no longer exists).

Why these specific HTTP status codes?

REST APIs use status codes to tell clients exactly what happened. 201 means "I created something new." 204 means "done, nothing to send back." 404 means "that thing doesn't exist." These conventions are how every REST API in the industry communicates results.

  • Save BookController.java.
  • Confirm there are no red underlines anywhere in the file. All five methods should sit inside the BookController class braces.

Seeing errors on ResponseEntity or HttpStatus?

Make sure you have both import org.springframework.http.HttpStatus; and import org.springframework.http.ResponseEntity; at the top of the file.

If VS Code shows a red underline on a method but not the imports, check that the method is inside the class curly braces. A misplaced closing brace is the most common cause.

Help me fix errors in my BookController methods.

✔️ Awesome, I've got everything!

Great. Double check you've saved BookController.java and confirm the file has no red underlines before moving on.

ⓧ I'd like to double check the full code

Here is the complete BookController.java file. Compare yours against this:

package com.example.bookstore;

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

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

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

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

    @GetMapping("/{id}")
    public ResponseEntity<Book> getBookById(@PathVariable Long id) {
        return books.stream()
                .filter(book -> book.getId().equals(id))
                .findFirst()
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }

    @PostMapping
    public ResponseEntity<Book> createBook(@RequestBody Book book) {
        book.setId(counter.incrementAndGet());
        books.add(book);
        return ResponseEntity.status(HttpStatus.CREATED).body(book);
    }

    @PutMapping("/{id}")
    public ResponseEntity<Book> updateBook(@PathVariable Long id, @RequestBody Book book) {
        for (int i = 0; i < books.size(); i++) {
            if (books.get(i).getId().equals(id)) {
                book.setId(id);
                books.set(i, book);
                return ResponseEntity.ok(book);
            }
        }
        return ResponseEntity.notFound().build();
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteBook(@PathVariable Long id) {
        boolean removed = books.removeIf(book -> book.getId().equals(id));
        if (removed) {
            return ResponseEntity.noContent().build();
        }
        return ResponseEntity.notFound().build();
    }

}

Your REST controller is complete with all five CRUD endpoints. In the next step, you'll fire up the server and test every endpoint with real HTTP requests from PowerShell.

Test Your API

Your Book model and BookController are complete. You now have a server with five endpoints ready to handle requests.

The real test of any REST API is whether it responds correctly to real HTTP requests. In this step, you will send requests using PowerShell's built-in Invoke-RestMethod command and verify the JSON responses.

In this step, get ready to:
  • Start the Spring Boot server and create a book with a POST request.
  • Retrieve books using GET requests from PowerShell and your browser.
  • Update and delete books to complete the full CRUD cycle.
Start the server and create a book

Before you can send requests, the server needs to be running. You started it once before in Step 1 to verify the project compiled. This time, you will keep it running while you test each endpoint.

  • Switch back to the terminal in VS Code and start the server by running this command:
.\mvnw.cmd spring-boot:run
  • Wait until you see Started BookstoreApplication in the output. This confirms the server is listening on port 8080.

Why keep this terminal running?

The Spring Boot server occupies the terminal it started in. As long as you see log output and no error, the server is alive and accepting requests. You will send those requests from a separate PowerShell window.

  • Open a new PowerShell window by pressing the Windows key, typing PowerShell, and pressing Enter.

This second window is where you will type all the test commands. Keep the VS Code terminal untouched so the server stays running.

  • Create your first book by running this command in the new PowerShell window:
Invoke-RestMethod -Uri "http://localhost:8080/api/books" -Method POST -ContentType "application/json" -Body '{"title":"The Great Gatsby","author":"F. Scott Fitzgerald","price":10.99}'
  • You should see output showing the book you just created, including an id of 1.

What does this command do?

Invoke-RestMethod is PowerShell's built-in tool for sending HTTP requests. Here is what each flag does:

  • -Uri sets the URL of the endpoint you are calling.
  • -Method POST tells the server you want to create a new resource.
  • -ContentType "application/json" tells the server the body is JSON data.
  • -Body contains the actual book data (title, author, price). The server assigns the id automatically.

Seeing a connection error?

  • Make sure the server is still running in your VS Code terminal. If you see an error or no output there, restart it with .\mvnw.cmd spring-boot:run.
  • Check that the URL uses http:// (not https://). Your local server does not use HTTPS.
  • Confirm port 8080 is not blocked by another application. If another process uses that port, you will see a startup error in the VS Code terminal.

Help me troubleshoot my Invoke-RestMethod connection error when calling my Spring Boot API on localhost:8080

Retrieve and list books

Your POST request proved the Create part of CRUD works. Now test the Read operations by fetching books back from the server.

  • Get a list of all books by running this command:
Invoke-RestMethod -Uri "http://localhost:8080/api/books" -Method GET
  • You should see The Great Gatsby returned in a list. This hits the getAllBooks() method in your controller.
  • Get a single book by its ID by running this command:
Invoke-RestMethod -Uri "http://localhost:8080/api/books/1" -Method GET
  • You should see only the single book with id of 1 returned. This hits the getBookById() method.
  • Open your browser and navigate to http://localhost:8080/api/books to see the same JSON response rendered in the browser.

Why does the browser work for GET requests?

When you type a URL into your browser's address bar, the browser sends a GET request. That is why you can view the JSON response directly. For POST, PUT, and DELETE requests you need a tool like PowerShell or a dedicated API client.

Update and delete a book

The last two CRUD operations are Update and Delete. These prove your API can modify existing data, not just create and read it.

  • Update the book's price from 10.99 to 12.99 by running this command:
Invoke-RestMethod -Uri "http://localhost:8080/api/books/1" -Method PUT -ContentType "application/json" -Body '{"title":"The Great Gatsby","author":"F. Scott Fitzgerald","price":12.99}'
  • You should see the book returned with the updated price of 12.99. The PUT method replaces the entire book object at that ID.
  • Delete the book by running this command:
Invoke-RestMethod -Uri "http://localhost:8080/api/books/1" -Method DELETE
  • This command produces no output. A successful DELETE returns a 204 No Content status, which means the server processed the request but has nothing to send back.
  • Verify the book is gone by running GET again:
Invoke-RestMethod -Uri "http://localhost:8080/api/books" -Method GET
  • You should see no output or an empty result. The book has been removed from the in-memory list.

What are HTTP status codes?

Every HTTP response includes a numeric status code. Your API uses three common ones:

  • 201 Created means a new resource was successfully created (POST).
  • 204 No Content means the action succeeded but there is nothing to return (DELETE).
  • 404 Not Found means the requested resource does not exist (wrong ID).

Getting a 404 on your PUT or DELETE?

  • Make sure you created a book first with the POST command. The in-memory list starts empty every time you restart the server.
  • Check that the ID in your URL matches the ID the server returned when you created the book. If you restarted the server between commands, IDs reset to 1.

Help me figure out why my PUT or DELETE request returns 404 when testing my Spring Boot Bookstore API

Secret mission

Add Search Functionality

Your API can create, read, update, and delete books. But what if someone wants to find all books by a specific author without scrolling through hundreds of results? Add a search endpoint that filters books by author or title using query parameters.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally, so there are no ongoing costs. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Resources you used:

  • The Spring Boot server running on localhost:8080.
  • The bookstore project folder on your computer.

Keep everything running

No action needed. Choose this if you're still actively building or want to continue experimenting with your API endpoints.

  • Your Spring Boot server will keep running until you close the terminal or press Ctrl+C.
  • Your bookstore project folder stays on your computer for future use.

Pause - I'll come back to this later

Stop the running server to free up the terminal. Your project files stay on your computer so you can restart any time.

  • Switch to the terminal where the Spring Boot server is running.
  • Press Ctrl+C to stop the server.
  • To restart later, open the bookstore folder in VS Code and run .\mvnw.cmd spring-boot:run in the terminal.

Delete - I don't want to use this again

Remove all project files and stop the server. This cannot be undone.

  • Switch to the terminal where the Spring Boot server is running and press Ctrl+C to stop it.
  • Delete the bookstore project folder. On macOS/Linux, run:
rm -rf ~/Desktop/bookstore

On Windows, run this in PowerShell:

Remove-Item -Recurse -Force ~\Desktop\bookstore

Folder in a different location?

If you extracted your project to a different folder than your Desktop, replace the path above with the actual location of your bookstore folder.

Nice Work!

Nice Work!

Nice work! You just built a fully functional REST API from scratch using Spring Boot, the most popular Java framework in the industry.

You've learned how to:

  • Built a Spring Boot project with proper Maven structure, a Book model class, and a full REST controller handling CRUD operations.
  • Mapped HTTP methods to Java methods using annotations like @RestController, @GetMapping, @PostMapping, @PutMapping, and @DeleteMapping.
  • Tested every endpoint using PowerShell's Invoke-RestMethod to create, read, update, and delete books through your running API.
  • Added search functionality with query parameters, filtering books by author or title using Java streams.

Ready to quiz yourself?