Implementing READ operation
In this step, we'll implement two methods at once. One is for retrieving a single post and another for multiple blog
posts. By completing this step, you'll learn to map your service with the HTTP GET (@Get) method, use parameter injection (@Param), set default parameter value (@Default), and return a JSON object (@ProducesJson) as a response.
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.javaBlogPost.javaBlogService.javaBlogServiceTest.java
1. Map HTTP method
Let's start mapping the HTTP GET method with our service method:
- Single post
- Multiple posts
Map the HTTP GET method for retrieving a single post:
- Declare a service method
getBlogPost()in the classBlogService. - Map this service method with the HTTP GET method by adding the
@Getannotation as follows. - Bind the endpoint
/blogsto the method.
import com.linecorp.armeria.server.annotation.Get;
public final class BlogService {
...
@Get("/blogs")
public void getBlogPost(int id) {
// Retrieve a single post
}
}
Map the HTTP GET method for retrieving multiple posts:
- Declare a service method
getBlogPosts()in the classBlogService. - Map this service method with the HTTP GET method by adding the
@Getannotation as follows. - Bind the endpoint
/blogsto the method.
import com.linecorp.armeria.server.annotation.Get;
public final class BlogService {
...
@Get("/blogs")
public void getBlogPosts(boolean descending) {
// Retrieve multiple posts
}
}
2. Handle parameters
Take in information through path and query parameters for retrieving blog posts. For retrieving a single post, we'll take a blog post ID as the path parameter. For multiple posts, we'll take the sorting order as a query parameter.
- Single post
- Multiple posts
Let's handle parameters for retrieving a single post:
- To take in a path parameter, add
/:idto the@Getannotation's parameter as in line 6. - Inject the path parameter to the service method, annotate the parameter with
@Paramas in line 7.
import com.linecorp.armeria.server.annotation.Param;
public final class BlogService {
...
@Get("/blogs/:id")
public void getBlogPost(@Param int id) {
// Retrieve a single post
}
}
Let's handle parameters for retrieving multiple posts:
- Specify the endpoint for the service using the
@Getannotation. - Inject the parameter by annotating the parameter
descendingwith@Paramas in line 8. - Set the default sorting order to descending by annotating the parameter
descendingwith@Default, with its parameter as"true".
import com.linecorp.armeria.server.annotation.Param;
import com.linecorp.armeria.server.annotation.Default;
public final class BlogService {
...
@Get("/blogs")
public void getBlogPosts(@Param @Default("true") boolean descending) {
// Retrieve multiple posts
}
}
3. Implement service code
In this step, write the code required for service itself.
- Single post
- Multiple posts
To retrieve a single blog post information, copy the following code inside the getBlogPost() method.
@Get("/blogs")
public void getBlogPost(@Param int id) {
BlogPost blogPost = blogPosts.get(id);
}
To retrieve multiple blog posts, copy the following code inside the getBlogPosts() method. Note that the return type has been changed from void to Iterable<BlogPost>.
import java.util.Map.Entry;
import java.util.Collections;
import java.util.Comparator;
import java.util.stream.Collectors;
@Get("/blogs")
public Iterable<BlogPost> getBlogPosts(@Param @Default("true") boolean descending) {
// Descending
if (descending) {
return blogPosts.entrySet()
.stream()
.sorted(Collections.reverseOrder(Comparator.comparingInt(Entry::getKey)))
.map(Entry::getValue).collect(Collectors.toList());
}
// Ascending
return blogPosts.values().stream().collect(Collectors.toList());
}
4. Return response
Let's return a response for the service call.
- Single post
- Multiple posts
To return a response for getting a single post:
- Replace the return type of the
getBlogPost()method fromvoidtoHttpResponse. - Return a response using Armeria's
HttpResponsecontaining the content of the blog post retrieved.
import com.linecorp.armeria.common.HttpResponse;
public final class BlogService {
@Get("/blogs/:id")
public HttpResponse getBlogPost(@Param int id) {
...
return HttpResponse.ofJson(blogPost);
}
}
We've already implemented returning multiple blog posts in the previous step. Here, annotate the method getBlogPosts() with @ProducesJson. This converts a list of BlogPost objects into a JSON response.
import com.linecorp.armeria.server.annotation.ProducesJson;
@Get("/blogs")
@ProducesJson
public Iterable<BlogPost> getBlogPosts(@Param @Default("true") boolean descending) {
// Retrieve multiple blog posts
}
5. Test retrieving a single post
Let's test if we can retrieve a blog post we created.
- In the
BlogServiceTestclass, add a test method to retrieve the first blog post with ID0.
@Test
void getBlogPost() throws JsonProcessingException {
final WebClient client = WebClient.of(server.httpUri());
final AggregatedHttpResponse res = client.get("/blogs/0").aggregate().join();
final Map<String, Object> expected = Map.of("id", 0,
"title", "My first blog",
"content", "Hello Armeria!");
assertThatJson(res.contentUtf8()).whenIgnoringPaths("createdAt", "modifiedAt")
.isEqualTo(mapper.writeValueAsString(expected));
}
- Add annotations to configure the order our test methods will be executed.
The annotations guarantee that the first blog post will be created in the
createBlogPost()method before we try to retrieve it in thegetBlogPost()method.
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.TestMethodOrder;
@TestMethodOrder(OrderAnnotation.class) // Add this
class BlogServiceTest {
...
@Test
@Order(1) // Add this
void createBlogPost() throws JsonProcessingException {
...
}
@Test
@Order(2) // Add this
void getBlogPost() throws JsonProcessingException {
...
}
}
- Run all the test cases on your IDE or using Gradle.
Your client retrieved a blog post from the server successfully if the test is passed.
6. Test retrieving multiple posts
Finally, let's test if we can retrieve multiple posts. Add a test method like the following to create the second blog post and test retrieving the list of blog posts.
import java.util.List;
@Test
@Order(3)
void getBlogPosts() throws JsonProcessingException {
final WebClient client = WebClient.of(server.httpUri());
final HttpRequest request = createBlogPostRequest(Map.of("title", "My second blog",
"content", "Armeria is awesome!"));
client.execute(request).aggregate().join();
final AggregatedHttpResponse res = client.get("/blogs").aggregate().join();
final List<Map<String, Object>> expected = List.of(
Map.of("id", 1,
"title", "My second blog",
"content", "Armeria is awesome!"),
Map.of("id", 0,
"title", "My first blog",
"content", "Hello 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 methods for a READ operation and used Armeria's annotations; @Get, @ProducesJson, @Param, and @Default.
Next, at Step 6. Implement UPDATE, we'll implement an UPDATE operation to modify existing blog posts.