Skip to main content

Implementing UPDATE operation

Previously, we created and read blog posts. Now, let's implement and make a call to update a blog post. We'll also learn how to handle an exception with a custom exception handler.

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.

1. Implement server-side​

Let's implement the server-side for updating blog posts. This time, we'll use a custom exception handler.

Add an exception handler​

First, add a custom exception handler for the blog service.

  1. Create a class for the exception to be thrown when a specified blog post ID doesn't exist.
BlogNotFoundException.java
package example.armeria.server.blog.grpc;

final class BlogNotFoundException extends IllegalStateException {
BlogNotFoundException(String s) {
super(s);
}
}
  1. Add an exception handler class for the blog service.
GrpcExceptionHandler.java
package example.armeria.server.blog.grpc;

import com.linecorp.armeria.common.RequestContext;
import com.linecorp.armeria.common.annotation.Nullable;
import com.linecorp.armeria.common.grpc.GrpcExceptionHandlerFunction;

import io.grpc.Metadata;
import io.grpc.Status;

public class GrpcExceptionHandler implements GrpcExceptionHandlerFunction {

@Nullable
@Override
public Status apply(RequestContext ctx, Throwable cause, Metadata metadata) {
if (cause instanceof IllegalArgumentException) {
return Status.INVALID_ARGUMENT.withCause(cause);
}
if (cause instanceof BlogNotFoundException) {
return Status.NOT_FOUND.withCause(cause).withDescription(cause.getMessage());
}

// The default mapping function will be applied.
return null;
}
}
  1. In the Main class, bind the GrpcExceptionHandler to our service.
Main.java
private static Server newServer(int port) throws Exception {
final GrpcService grpcService =
GrpcService.builder()
.addService(new BlogService())
.exceptionMapping(new GrpcExceptionHandler()) // Add this
.build();
...
}

Implement the service method​

In the BlogServiceImpl class, add a service method for updating a blog post.

BlogService.java
import example.armeria.blog.grpc.UpdateBlogPostRequest;

public class BlogService extends BlogServiceGrpc.BlogServiceImplBase {
@Override
public void updateBlogPost(UpdateBlogPostRequest request, StreamObserver<BlogPost> responseObserver) {
final BlogPost oldBlogPost = blogPosts.get(request.getId());
if (oldBlogPost == null) {
throw new BlogNotFoundException("The blog post does not exist. ID: " + request.getId());
} else {
final BlogPost newBlogPost = oldBlogPost.toBuilder()
.setTitle(request.getTitle())
.setContent(request.getContent())
.setModifiedAt(Instant.now().toEpochMilli())
.build();
blogPosts.put(request.getId(), newBlogPost);
responseObserver.onNext(newBlogPost);
responseObserver.onCompleted();
}
}
}

3. Test updating a blog post​

Let's try updating the content of the first blog post. Add a method like the following.

BlogServiceTest.java
@Test
@Order(5)
void updateBlogPosts() throws JsonProcessingException {
final UpdateBlogPostRequest request = UpdateBlogPostRequest.newBuilder()
.setId(0)
.setTitle("My first blog")
.setContent("Hello awesome Armeria!")
.build();
final BlogPost updated = client.updateBlogPost(request);
assertThat(updated.getId()).isZero();
assertThat(updated.getTitle()).isEqualTo("My first blog");
assertThat(updated.getContent()).isEqualTo("Hello awesome Armeria!");
}

Run all the test cases on your IDE or using Gradle. Check that you see the test is passed.

4. Test an error case​

To check that our exception handler is working, let's try updating a post which does not exist.

  1. Bind the exception handler to the service for the test server.
BlogServiceTest.java
@RegisterExtension
static final ServerExtension server = new ServerExtension() {
@Override
protected void configure(ServerBuilder sb) throws Exception {
sb.service(GrpcService.builder()
.addService(new BlogService())
.exceptionHandler(new GrpcExceptionHandler()) // Add this
.build());
}
};
  1. Add a test method to update a blog post with an invalid ID, asserting an exception is thrown as expected.
BlogServiceTest.java
@Test
@Order(6)
void updateInvalidBlogPost() {
final Throwable exception = catchThrowable(() -> {
client.updateBlogPost(UpdateBlogPostRequest.newBuilder()
.setId(Integer.MAX_VALUE)
.setTitle("My first blog")
.setContent("Hello awesome Armeria!")
.build());
});
final StatusRuntimeException statusException = (StatusRuntimeException) exception;
assertThat(statusException.getStatus().getCode()).isEqualTo(Code.NOT_FOUND);
assertThat(statusException)
.hasMessageContaining("The blog post does not exist. ID: " + Integer.MAX_VALUE);
}
  1. Run all the test cases on your IDE or using Gradle. Check that you see the test is passed.

What's next​

In this step, we've implemented a service method for updating a blog post. We've also added an exception handler.

Next, at Step 6. Implement DELETE, we'll implement a method for deleting a blog post and add a Documentation Service to our service.

Like Armeria?
Star us ⭐️

×