The RSS reader tutorial. Step 2.
Quick recap
In the previous step we have successfully implemented the first endpoint of the RSS reader app.
The RSS reader example assumes implementing 3 endpoints. This article is dedicated to implementing the GET /user/{user_id}/rss_channels
endpoint.
Before completing this step, make sure your are in the step_2
git branch:
git checkout step_2
Implementing the second endpoint
The second endpoint produces an array of RSS channels by given user_id
.
We need to execute the two following queries to:
- Fetch RSS links for a given user:
SELECT rss_link FROM rss_by_user WHERE login = GIVEN_USER_ID ;
- Fetch RSS channel details for a given link:
SELECT description, title, site_link, rss_link FROM channel_info_by_rss_link WHERE rss_link = GIVEN_LINK ;
Implementation
The endpoint allows the the front-end app to display the list of RSS feeds a user subscribed on. When the endpoint is accessed, the AppVerticle#getRssChannels
method is called. We can implement this method in this way:
private void getRssChannels(RoutingContext ctx) {
String userId = ctx.request().getParam("user_id");
if (userId == null) {
responseWithInvalidRequest(ctx);
} else {
Future<List<Row>> future = Future.future();
client.executeWithFullFetch(selectRssLinksByLogin.bind(userId), future);
future.compose(rows -> {
List<String> links = rows.stream()
.map(row -> row.getString(0))
.collect(Collectors.toList());
return CompositeFuture.all(
links.stream().map(selectChannelInfo::bind).map(statement -> {
Future<List<Row>> channelInfoRow = Future.future();
client.executeWithFullFetch(statement, channelInfoRow);
return channelInfoRow;
}).collect(Collectors.toList())
);
}).setHandler(h -> {
if (h.succeeded()) {
CompositeFuture result = h.result();
List<List<Row>> results = result.list();
List<Row> list = results.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
JsonObject responseJson = new JsonObject();
JsonArray channels = new JsonArray();
list.forEach(eachRow -> channels.add(
new JsonObject()
.put("description", eachRow.getString(0))
.put("title", eachRow.getString(1))
.put("link", eachRow.getString(2))
.put("rss_link", eachRow.getString(3))
));
responseJson.put("channels", channels);
ctx.response().end(responseJson.toString());
} else {
log.error("failed to get rss channels", h.cause());
ctx.response().setStatusCode(500).end("Unable to retrieve the info from C*");
}
});
}
}
Also, this method uses selectChannelInfo
and selectRssLinksByLogin
fields, they should be initialized in the AppVerticle#prepareNecessaryQueries
method:
private Future<Void> prepareNecessaryQueries() {
Future<PreparedStatement> selectChannelInfoPrepFuture = Future.future();
client.prepare("SELECT description, title, site_link, rss_link FROM channel_info_by_rss_link WHERE rss_link = ? ;", selectChannelInfoPrepFuture);
Future<PreparedStatement> selectRssLinkByLoginPrepFuture = Future.future();
client.prepare("SELECT rss_link FROM rss_by_user WHERE login = ? ;", selectRssLinkByLoginPrepFuture);
Future<PreparedStatement> insertNewLinkForUserPrepFuture = Future.future();
client.prepare("INSERT INTO rss_by_user (login , rss_link ) VALUES ( ?, ?);", insertNewLinkForUserPrepFuture);
return CompositeFuture.all(
selectChannelInfoPrepFuture.compose(preparedStatement -> {
selectChannelInfo = preparedStatement;
return Future.succeededFuture();
}),
selectRssLinkByLoginPrepFuture.compose(preparedStatement -> {
selectRssLinksByLogin = preparedStatement;
return Future.succeededFuture();
}),
insertNewLinkForUserPrepFuture.compose(preparedStatement -> {
insertNewLinkForUser = preparedStatement;
return Future.succeededFuture();
})
).mapEmpty();
}
Conclusion
In this part, we have successfully implemented the second endpoint, which allows the browser app to obtain channels information for a specific user. To ensure that it is working fine, point your browser to localhost:8080
and click to the refresh button. Channel list should appear immediately.
If you have any problems with completing this step you can checkout to step_3
, where you can find all changes made for completing this step:
git checkout step_3
Thanks for reading this. I hope you enjoyed reading this article. See you soon on our Gitter channel!