Check out the full series of Questions Management tutorial here.
As I mentioned earlier, in the previous tutorial, we have prepared all the necessary information and configurations to be able to build API updating category such as a document Category object containing information about a category, CategoryRepository to manipulate MongoDB, a CategoryController that defines the APIs of the Core Category Service will start with “/category” and the connection information to the MongoDB server is configured in the application.properties file. Now, we will proceed to build API to update a category.
To build API updating category, I would add a method to expose a PUT request “{id}” with the id being the category id that we need to update. We also need to define the body data, is the new content of the category that we will update as follows:
1 2 3 4 5 6 |
@PutMapping("/{id}") public Mono<ResponseEntity<Category>> updateCategory( @PathVariable(value = "id") String categoryId, @RequestBody Category category) { } |
The steps to update a category include:
First, we need to check that the category we need to update does exist or not based on the id that the user is passing.
Spring Data MongoDB Reactive has provided us with a way to search by id so we just need to call it.
1 |
categoryRepository.findById(categoryId) |
In case this category exists, we will use the information passed in the body data to update the information in the database:
1 2 3 4 5 6 7 8 |
categoryRepository.findById(categoryId) .flatMap(existingCategory -> { existingCategory.setCode(category.getCode()); existingCategory.setName(category.getName()); existingCategory.setDescription(category.getDescription()); return categoryRepository.save(existingCategory); }) |
Then returning to the user the new information of this category after updating the database with the HTTP status code of 200 OK.
1 2 3 4 5 6 7 8 9 |
categoryRepository.findById(categoryId) .flatMap(existingCategory -> { existingCategory.setCode(category.getCode()); existingCategory.setName(category.getName()); existingCategory.setDescription(category.getDescription()); return categoryRepository.save(existingCategory); }) .map(updatedCategory -> new ResponseEntity<>(updatedCategory, HttpStatus.OK)) |
In case this category does not exist in the database, we will return the result of HTTP status code is 404 Not Found.
1 2 3 4 5 6 7 8 9 10 |
categoryRepository.findById(categoryId) .flatMap(existingCategory -> { existingCategory.setCode(category.getCode()); existingCategory.setName(category.getName()); existingCategory.setDescription(category.getDescription()); return categoryRepository.save(existingCategory); }) .map(updatedCategory -> new ResponseEntity<>(updatedCategory, HttpStatus.OK)) .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND)); |
The entire content of the updateCategory() method will now look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@PutMapping("/{id}") public Mono<ResponseEntity<Category>> updateCategory( @PathVariable(value = "id") String categoryId, @RequestBody Category category) { return categoryRepository.findById(categoryId) .flatMap(existingCategory -> { existingCategory.setCode(category.getCode()); existingCategory.setName(category.getName()); existingCategory.setDescription(category.getDescription()); return categoryRepository.save(existingCategory); }) .map(updatedCategory -> new ResponseEntity<>(updatedCategory, HttpStatus.OK)) .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND)); } |
Now that we’ve finished building the API to update a category for the Core Category Service, let’s try it out.
Suppose currently in the database I have the following categories:
then when I request to update the category with id is 5b297751366e2605cf3c0d3e:
The result will be:
Now we will add a new Unit Test for the code that we just added.
In the previous tutorial, I created a new test class for CategoryController called CategoryControllerTest, a Mock object for CategoryRepository, and injected this Mock object into the CategoryController class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.huongdanjava.categoryservice; import org.mockito.InjectMocks; import org.mockito.Mock; import com.huongdanjava.categoryservice.repository.CategoryRepository; public class CategoryControllerTest { @Mock private CategoryRepository categoryRepository; @InjectMocks private CategoryController categoryController; } |
Initialize mock every time I run a test case:
1 2 3 4 |
@Before public void init() { MockitoAnnotations.initMocks(this); } |
Now we will add two methods to test for the updateCategory() method of the CategoryController class as follows:
A method to test if there is a category based on passing id:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
@Test public void testUpdateExistingCategory() { // Create category document to return when using findById Category category = new Category(); category.setId("123"); category.setCode("ABC"); category.setName("ZXC"); // Category information need to be updated Category updateCategory = new Category(); updateCategory.setId("123"); updateCategory.setCode("ABC"); updateCategory.setName("ZXCV"); // Mock findById() method of CategoryRepository to return above category when(categoryRepository.findById("123")).thenReturn(Mono.just(category)); // Mock save() method of CategoryRepository when(categoryRepository.save(category)).thenReturn(Mono.just(updateCategory)); // Call method Mono<ResponseEntity<Category>> update = categoryController.updateCategory("123", updateCategory); ResponseEntity<Category> responseEntity = update.block(); // Assertions assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); Category responseCategory = responseEntity.getBody(); assertEquals("ZXCV", responseCategory.getName()); } |
A method to test for the absence of category based on passing id:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@Test public void testUpdateNoExistingCategory() { // Category information need to be updated Category updateCategory = new Category(); updateCategory.setId("123"); updateCategory.setCode("ABC"); updateCategory.setName("ZXCV"); // Mock findById() method of CategoryRepository to return an empty Mono when(categoryRepository.findById("123")).thenReturn(Mono.empty()); // Call method Mono<ResponseEntity<Category>> update = categoryController.updateCategory("123", updateCategory); ResponseEntity<Category> responseEntity = update.block(); // Assertions assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); } |
Run “Maven test” in STS or “mvn test” with Apache Maven, you will not see any errors.