CRUD REST API with Spring Boot
Prerequisites: You should have completed Exercise 02 (Modelling an API) where you created a Book API with nested Author and Publisher objects.
Starting Point
You should already have:
- Model classes:
Book,Author, andPublisher BookControllerwith:GET /api/books- Returns list of booksGET /api/books/{id}- Returns single book or 404
Now you will extend this API with CREATE, UPDATE, and DELETE operations.
Exercise 1 - Bonus: Customize JSON output order
Goal: Learn how to customize the order of fields in the JSON response.
- In the
Bookclass, use a Jackson annotation to specify the order of fields in the JSON output so thatidcomes first, followed bytitle,isbn,publishedYear,edition,author, and thenpublisher.- Hint: Use the
@JsonPropertyOrder({"id", "title", "isbn", "publishedYear", "edition", "author", "publisher"})annotation on theBookclass.
- Hint: Use the
- Test the
/api/booksand/api/books/{id}endpoints again to verify that the JSON output reflects the specified field order. - (Optional) Apply similar ordering to the
AuthorandPublisherclasses. - Test the endpoints again to verify the changes.
Exercise 2 - POST, PUT, DELETE Operations
Goal: Fully implement CRUD operations for the Book resource.
2.1 - POST endpoint
- Create a new endpoint
POST /api/booksin theBookControllerthat accepts aBookobject in the request body and returns the same book with a201 Createdstatus code. The ID should be auto-generated (you can simulate this by incrementing a static variable).- Hint: Use the
@RequestBodyannotation to bind the incoming JSON to aBookobject. - Hint: Use
@PostMappingfor POST endpoints. - Hint: Use
AtomicLongorLongfor generating unique IDs.
- Hint: Use the
- Test the endpoint using Postman by sending a
POSTrequest tohttp://localhost:8080/api/bookswith a JSON body representing a new book (without an ID). Verify that the response contains the created book with an assigned ID. - Add a
Locationheader to the response that points to the URL of the newly created book (e.g.,/api/books/{id}).- Hint: You can use
ResponseEntity.created(URI.create("/api/books/" + book.getId())).body(book)to set theLocationheader.
- Hint: You can use
2.2 - PUT endpoint
- Create a new endpoint
PUT /api/books/{id}in theBookControllerthat accepts aBookobject in the request body and updates the existing book with the specified ID. - If the book with the specified ID does not exist, return a
404 Not Foundresponse. - Test the endpoint using Postman by sending a
PUTrequest tohttp://localhost:8080/api/books/{id}with a JSON body representing the updated book data. Verify that the response contains the updated book.
2.3 - DELETE endpoint
- Create a new endpoint
DELETE /api/books/{id}in theBookControllerthat deletes the book with the specified ID and returns a204 No Contentstatus code. - If the book with the specified ID does not exist, return a
204 No Contentresponse. - Test the endpoint using Postman by sending a
DELETErequest tohttp://localhost:8080/api/books/{id}. Verify that the response status code is204 No Content.
Exercise 3 - Testing Your Complete API
Now that you have a full CRUD API, test all operations in sequence:
- GET
/api/books- Verify you see your initial 3+ books - POST
/api/books- Add a new book (e.g., "Clean Code" by Robert C. Martin) - GET
/api/books- Verify the new book appears in the list - GET
/api/books/{id}- Retrieve the specific book you just created - PUT
/api/books/{id}- Update the book (e.g., change the edition) - GET
/api/books/{id}- Verify the update was successful - DELETE
/api/books/{id}- Delete the book - GET
/api/books/{id}- Verify you get a 404 Not Found