Implementing UPDATE operation
Table of contents
In this step, you'll write a method for updating a blog post. By completing this step, you'll learn to map your service with the HTTP PUT (@Put
) method, use parameter injection, and convert request body into a Java object using a request object (@RequestObject
).
What you need
You need to have the following files obtained from previous steps. You can always download the full version, instead of creating one yourself.
Main.java
BlogPost.java
BlogService.java
BlogServiceTest.java
1. Map HTTP method
Let's start mapping the HTTP PUT method with our service method:
- Declare a service method,
updateBlogPost()
, in the classBlogService
. - Map this service method with the HTTP PUT method by adding the
@Put
annotation. - Bind the endpoint
/blogs
to the method.
import com.linecorp.armeria.server.annotation.Put;
public final class BlogService {
...
@Put("/blogs")
public void updateBlogPost(int id, BlogPost blogPost) {
// Update a blog post
}
}
2. Handle parameters
For updating a blog post, let's take a blog post ID (id
) and new blog post information to update with. For creating a blog post, we've used Armeria's RequestConverter
to convert a request body into a Java object. For a change, let's try using @RequestObject
to convert a request body.
Take in the ID value as a path parameter by adding
/blogs/:id
to the@Put
annotation.Inject the path parameter to the service method by annotating the parameter with
@Param
.Convert request body into a Java object by annotating the
BlogPost
parameter with@RequestObject
.BlogService.javaimport com.linecorp.armeria.server.annotation.Param; import com.linecorp.armeria.server.annotation.RequestObject; public final class BlogService { ... // Instructions 1 to 3 @Put("/blogs/:id") public void updateBlogPost(@Param int id, @RequestObject BlogPost blogPost) { // Update a blog post } }
For conversion, annotate blog post constructor to map JSON object keys to blog post object members. You can find more information on
@JsonCreator
here.BlogPost.javaimport com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; public final class BlogPost { ... @JsonCreator BlogPost(@JsonProperty("id") int id, @JsonProperty("title") String title, @JsonProperty("content") String content) { ... } }
3. Implement service code
In this step, write the code required for service itself. You need to update the information contained in the blogPosts
map. In real services, you'll be retrieving and updating the blog post information from and to a database.
To update a blog post, copy the following code inside the updateBlogPost()
method.
@Put("/blogs/:id")
public void updateBlogPost(@Param int id, @RequestObject BlogPost blogPost) {
BlogPost oldBlogPost = blogPosts.get(id);
// Check if the given blog post exists
if (oldBlogPost == null) {
// Return a Not Found error. See the next section for instructions
}
BlogPost newBlogPost = new BlogPost(id, blogPost.getTitle(),
blogPost.getContent(),
oldBlogPost.getCreatedAt(),
blogPost.getCreatedAt());
blogPosts.put(id, newBlogPost); // Update the info in the map
...
}
4. Return response
Two possibilities are available for the response. If the blog post to update exists, we respond to the client that the update has been successful. The other response informs the client that the blog post doesn't exist.
Return error
Let's return an error for the request to update a blog post that doesn't exist.
- Replace the return type of the
updateBlogPost()
method fromvoid
toHttpResponse
. - Return a response using Armeria's
HttpResponse
containingHttpStatus.NOT_FOUND
.
import com.linecorp.armeria.common.HttpResponse;
import com.linecorp.armeria.common.HttpStatus;
public final class BlogService {
...
@Put("/blogs/:id")
public HttpResponse updateBlogPost(@Param int id, @RequestObject BlogPost blogPost) {
...
if (oldBlogPost == null) {
return HttpResponse.of(HttpStatus.NOT_FOUND);
}
...
}
}
Return success
Let's return the information updated when the target blog post exists:
- Replace the return type of the
updateBlogPost()
method fromvoid
toHttpResponse
. - Return a response using Armeria's
HttpResponse
containing the updated information of the post.
import com.linecorp.armeria.common.HttpResponse;
public final class BlogService {
...
@Put("/blogs/:id")
public HttpResponse updateBlogPost(@Param int id, @RequestObject BlogPost blogPost) {
...
return HttpResponse.ofJson(newBlogPost);
}
}
5. Test updating a blog post
Let's try updating the content of the first blog post. Add a method like the following.
@Test
@Order(4)
void updateBlogPosts() throws JsonProcessingException {
final WebClient client = WebClient.of(server.httpUri());
final Map<String, Object> updatedContent = Map.of("id", 0,
"title", "My first blog",
"content", "Hello awesome Armeria!");
final HttpRequest updateBlogPostRequest =
HttpRequest.builder()
.put("/blogs/0")
.content(MediaType.JSON_UTF_8, mapper.writeValueAsString(updatedContent))
.build();
client.execute(updateBlogPostRequest).aggregate().join();
final AggregatedHttpResponse res = client.get("/blogs/0").aggregate().join();
final Map<String, Object> expected = Map.of("id", 0,
"title", "My first blog",
"content", "Hello awesome Armeria!");
assertThatJson(res.contentUtf8()).whenIgnoringPaths("createdAt", "modifiedAt")
.isEqualTo(mapper.writeValueAsString(expected));
}
Run all the test cases on your IDE or using Gradle. Check that you see the test is passed.
You can test this also with Armeria's Documentation service. See Using DocService after adding service methods for instructions.
Next step
In this step, we've implemented a method for an UPDATE operation and used Armeria's annotations; @Put
, @Param
, and @RequestObject
.
Next, at Step 7. Implement DELETE, we'll implement a DELETE operation to delete blog posts.