Building a REST API with Spring Boot
This chapter builds a complete CRUD REST API for our Bookstore. You’ll learn @RestController, HTTP method mapping, JSON serialization, and how to test endpoints.
REST Basics
| HTTP Method | Operation | Example |
|---|---|---|
GET |
Read | GET /api/books |
POST |
Create | POST /api/books |
PUT |
Full update | PUT /api/books/1 |
PATCH |
Partial update | PATCH /api/books/1 |
DELETE |
Delete | DELETE /api/books/1 |
The Entity
@Entity
@Table(name = "books")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String author;
@Column(unique = true)
private String isbn;
private BigDecimal price;
private LocalDate publishedDate;
// Constructors, getters, setters
public Book() {}
public Book(String title, String author, String isbn, BigDecimal price) {
this.title = title;
this.author = author;
this.isbn = isbn;
this.price = price;
}
// getters and setters...
}
The Repository
public interface BookRepository extends JpaRepository<Book, Long> {
}
The Service
@Service
public class BookService {
private final BookRepository bookRepository;
public BookService(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
public List<Book> findAll() {
return bookRepository.findAll();
}
public Book findById(Long id) {
return bookRepository.findById(id)
.orElseThrow(() -> new ResponseStatusException(
HttpStatus.NOT_FOUND, "Book not found with id: " + id));
}
public Book create(Book book) {
return bookRepository.save(book);
}
public Book update(Long id, Book updated) {
Book book = findById(id);
book.setTitle(updated.getTitle());
book.setAuthor(updated.getAuthor());
book.setIsbn(updated.getIsbn());
book.setPrice(updated.getPrice());
return bookRepository.save(book);
}
public void delete(Long id) {
Book book = findById(id);
bookRepository.delete(book);
}
}
The Controller
@RestController
@RequestMapping("/api/books")
public class BookController {
private final BookService bookService;
public BookController(BookService bookService) {
this.bookService = bookService;
}
@GetMapping
public List<Book> getAll() {
return bookService.findAll();
}
@GetMapping("/{id}")
public Book getById(@PathVariable Long id) {
return bookService.findById(id);
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Book create(@RequestBody Book book) {
return bookService.create(book);
}
@PutMapping("/{id}")
public Book update(@PathVariable Long id, @RequestBody Book book) {
return bookService.update(id, book);
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(@PathVariable Long id) {
bookService.delete(id);
}
}
Testing with curl
# Create a book
curl -X POST http://localhost:8080/api/books \
-H "Content-Type: application/json" \
-d '{"title":"Clean Code","author":"Robert Martin","isbn":"978-0132350884","price":39.99}'
# Get all books
curl http://localhost:8080/api/books
# Get by ID
curl http://localhost:8080/api/books/1
# Update
curl -X PUT http://localhost:8080/api/books/1 \
-H "Content-Type: application/json" \
-d '{"title":"Clean Code","author":"Robert C. Martin","isbn":"978-0132350884","price":34.99}'
# Delete
curl -X DELETE http://localhost:8080/api/books/1
JSON Serialization (Jackson)
Spring Boot uses Jackson to convert Java objects ↔ JSON automatically:
// Java object
Book book = new Book("Clean Code", "Robert Martin", "978-0132350884", new BigDecimal("39.99"));
{
"id": 1,
"title": "Clean Code",
"author": "Robert Martin",
"isbn": "978-0132350884",
"price": 39.99,
"publishedDate": null
}
Customizing Jackson
// Exclude null fields
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Book { }
// Rename a field
@JsonProperty("book_title")
private String title;
// Ignore a field
@JsonIgnore
private String internalCode;
// Date format
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate publishedDate;
Response Status Codes
| Operation | Success Code | Error Code |
|---|---|---|
| GET (found) | 200 OK |
404 Not Found |
| POST (created) | 201 Created |
400 Bad Request |
| PUT (updated) | 200 OK |
404 Not Found |
| DELETE | 204 No Content |
404 Not Found |
Key Takeaways
@RestController+@RequestMapping= REST API endpoint.- Jackson handles JSON serialization/deserialization automatically.
- Use
@ResponseStatusto set HTTP status codes. - Follow REST conventions: proper HTTP methods, meaningful URLs, correct status codes.
- Layer: Controller → Service → Repository.
What’s Next?
Next: REST Annotations Deep Dive — @GetMapping, ResponseEntity, content negotiation.