Skip to content

Commit

Permalink
Refactored code base to be fully reactive and added rating figure (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
gdevxy committed Dec 28, 2024
1 parent f42d4ee commit d15b6c8
Show file tree
Hide file tree
Showing 41 changed files with 400 additions and 158 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,25 @@
import java.nio.charset.StandardCharsets;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import io.quarkus.cache.CacheResult;
import io.smallrye.mutiny.Uni;
import io.vertx.core.Vertx;
import lombok.SneakyThrows;

@ApplicationScoped
public class GraphQlQueryLoader {

@Inject
Vertx vertx;

@SneakyThrows
@CacheResult(cacheName = "graphql-query")
public String loadQuery(String queryName) {
public Uni<String> loadQuery(String queryName) {

try(var is = this.getClass().getResourceAsStream("/graphql/%s.graphql".formatted(queryName))) {
return new String(is.readAllBytes(), StandardCharsets.UTF_8);
}
return Uni.createFrom().future(vertx.fileSystem().readFile("graphql/%s.graphql".formatted(queryName)).toCompletionStage().toCompletableFuture())
.map(b -> b.toString(StandardCharsets.UTF_8));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import jakarta.ws.rs.Path;

import com.gdevxy.blog.client.contentful.model.PageBlogModel;
import io.smallrye.mutiny.Uni;
import org.eclipse.microprofile.faulttolerance.Retry;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

Expand All @@ -13,6 +14,6 @@ public interface ContentfulCMAClient {
@GET
@Retry(maxRetries = 2)
@Path("/content_types/pageBlogPost")
PageBlogModel findPageBlogModel();
Uni<PageBlogModel> findPageBlogModel();

}
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
package com.gdevxy.blog.client.contentful;

import java.util.Optional;
import java.util.Set;

import com.gdevxy.blog.client.contentful.model.ComponentRichImage;
import com.gdevxy.blog.client.contentful.model.PageBlogPost;
import com.gdevxy.blog.client.contentful.model.PageBlogPostCollection;
import com.gdevxy.blog.client.contentful.model.Pagination;
import com.gdevxy.blog.client.contentful.model.RecentPageBlogPostCollection;

import java.util.Optional;
import java.util.Set;
import io.smallrye.mutiny.Uni;

public interface ContentfulClient {

Optional<PageBlogPost> findBlogPost(String slug);
Uni<PageBlogPost> findBlogPost(String slug);

Optional<PageBlogPost> findBlogPost(String slug, String previewToken);
Uni<PageBlogPost> findBlogPost(String slug, String previewToken);

PageBlogPostCollection findBlogPosts(Pagination pagination, Set<String> tags);
Uni<PageBlogPostCollection> findBlogPosts(Pagination pagination, Set<String> tags);

PageBlogPostCollection findBlogPosts(Pagination pagination, Set<String> tags, String previewToken);
Uni<PageBlogPostCollection> findBlogPosts(Pagination pagination, Set<String> tags, String previewToken);

RecentPageBlogPostCollection findRecentBlogPosts();
Uni<RecentPageBlogPostCollection> findRecentBlogPosts();

RecentPageBlogPostCollection findRecentBlogPosts(String previewToken);
Uni<RecentPageBlogPostCollection> findRecentBlogPosts(String previewToken);

Optional<ComponentRichImage> findImage(String id);
Uni<ComponentRichImage> findImage(String id);

Optional<ComponentRichImage> findImage(String id, String previewToken);
Uni<ComponentRichImage> findImage(String id, String previewToken);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;

import jakarta.annotation.Nullable;
import jakarta.ws.rs.core.HttpHeaders;

import io.smallrye.graphql.client.Response;
import io.smallrye.graphql.client.dynamic.api.DynamicGraphQLClient;
import io.smallrye.graphql.client.dynamic.api.DynamicGraphQLClientBuilder;
import io.smallrye.mutiny.Uni;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -27,33 +26,31 @@ public ContentfulClientSupport(DynamicGraphQLClient client) {
this.previewClient = DynamicGraphQLClientBuilder.newBuilder().configKey("contentful");
}

@SneakyThrows
Response executeQuery(Supplier<String> querySupplier, @Nullable String previewToken) {
Uni<Response> executeQueryAsync(String query, @Nullable String previewToken) {

return executeQuery(querySupplier, Map.of(), previewToken);
return executeQueryAsync(query, Map.of(), previewToken);
}

@SneakyThrows
Response executeQuery(Supplier<String> querySupplier, Map<String, Object> params, @Nullable String previewToken) {
Uni<Response> executeQueryAsync(String query, Map<String, Object> params, @Nullable String previewToken) {

if (previewToken == null) {
return executeQuery(client, querySupplier, params);
return client.executeAsync(query, params)
.map(this::throwErrorOnGraphqlException);
}

try (var client = previewClient.header(HttpHeaders.AUTHORIZATION, "Bearer %s".formatted(previewToken)).build()) {
return executeQuery(client, querySupplier, extendWithPreviewMode(params));
return client.executeAsync(query, extendWithPreviewMode(params))
.map(this::throwErrorOnGraphqlException);
}
}

private Response executeQuery(DynamicGraphQLClient client, Supplier<String> querySupplier, Map<String, Object> params) throws ExecutionException, InterruptedException {

var response = client.executeSync(querySupplier.get(), params);
private Response throwErrorOnGraphqlException(Response response) {

if (response.hasError()) {
log.warn("Contentful query failed: [{}]", response.getErrors());
throw new ContentfulQueryException();
}

return response;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.gdevxy.blog.client.contentful;

import java.util.Map;
import java.util.Optional;
import java.util.Set;

import jakarta.enterprise.context.ApplicationScoped;
Expand All @@ -14,6 +13,8 @@
import com.gdevxy.blog.client.contentful.model.RecentPageBlogPostCollection;
import io.smallrye.graphql.client.GraphQLClient;
import io.smallrye.graphql.client.dynamic.api.DynamicGraphQLClient;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import lombok.extern.slf4j.Slf4j;

@Slf4j
Expand All @@ -28,60 +29,62 @@ public DefaultContentfulClient(@GraphQLClient("contentful") DynamicGraphQLClient
}

@Override
public Optional<PageBlogPost> findBlogPost(String slug) {
public Uni<PageBlogPost> findBlogPost(String slug) {

return findBlogPost(slug, null);
}

@Override
public Optional<PageBlogPost> findBlogPost(String slug, String previewToken) {
public Uni<PageBlogPost> findBlogPost(String slug, String previewToken) {

var response = executeQuery(() -> queryLoader.loadQuery("find-blog-post"), Map.of("slug", slug), previewToken);

return response.getObject(PageBlogPostCollection.class, "pageBlogPostCollection").getItems().stream().findAny();
return queryLoader.loadQuery("find-blog-post")
.flatMap(query -> executeQueryAsync(query, Map.of("slug", slug), previewToken))
.onItem().transformToMulti(res -> Multi.createFrom().iterable(res.getObject(PageBlogPostCollection.class, "pageBlogPostCollection").getItems()))
.toUni();
}

@Override
public PageBlogPostCollection findBlogPosts(Pagination pagination, Set<String> tags) {
public Uni<PageBlogPostCollection> findBlogPosts(Pagination pagination, Set<String> tags) {

return findBlogPosts(pagination, tags, null);
}

@Override
public PageBlogPostCollection findBlogPosts(Pagination pagination, Set<String> tags, String previewToken) {
public Uni<PageBlogPostCollection> findBlogPosts(Pagination pagination, Set<String> tags, String previewToken) {

var params = Map.of("limit", pagination.getPageSize(), "skip", pagination.getOffset(), "tags", tags);
var response = executeQuery(() -> queryLoader.loadQuery("find-blog-posts"), params, previewToken);

return response.getObject(PageBlogPostCollection.class, "pageBlogPostCollection");
return queryLoader.loadQuery("find-blog-posts")
.flatMap(query -> executeQueryAsync(query, params, previewToken))
.map(res -> res.getObject(PageBlogPostCollection.class, "pageBlogPostCollection"));
}

@Override
public RecentPageBlogPostCollection findRecentBlogPosts() {
public Uni<RecentPageBlogPostCollection> findRecentBlogPosts() {

return findRecentBlogPosts(null);
}

@Override
public RecentPageBlogPostCollection findRecentBlogPosts(String previewToken) {

var response = executeQuery(() -> queryLoader.loadQuery("find-recent-blog-posts"), previewToken);
public Uni<RecentPageBlogPostCollection> findRecentBlogPosts(String previewToken) {

return response.getObject(RecentPageBlogPostCollection.class, "pageBlogPostCollection");
return queryLoader.loadQuery("find-recent-blog-posts")
.flatMap(query -> executeQueryAsync(query, previewToken))
.map(res -> res.getObject(RecentPageBlogPostCollection.class, "pageBlogPostCollection"));
}

@Override
public Optional<ComponentRichImage> findImage(String id) {
public Uni<ComponentRichImage> findImage(String id) {

return findImage(id, null);
}

@Override
public Optional<ComponentRichImage> findImage(String id, String previewToken) {

var response = executeQuery(() -> queryLoader.loadQuery("find-image"), Map.of("id", id), previewToken);
public Uni<ComponentRichImage> findImage(String id, String previewToken) {

return Optional.ofNullable(response.getObject(ComponentRichImage.class, "componentRichImage"));
return queryLoader.loadQuery("find-image")
.flatMap(query -> executeQueryAsync(query, Map.of("id", id), previewToken))
.map(res -> res.getObject(ComponentRichImage.class, "componentRichImage"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
@ToString
public class ComponentRichImage {

private Sys sys;
private FeaturedImage image;
private Boolean fullWidth;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
package com.gdevxy.blog.client.gravatar;

import com.gdevxy.blog.client.gravatar.model.Profile;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;

import com.gdevxy.blog.client.gravatar.model.Profile;
import io.smallrye.mutiny.Uni;
import org.eclipse.microprofile.faulttolerance.Retry;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient(configKey = "gravatar")
public interface GravatarClient {

@GET
@Retry(maxRetries = 2)
@Path("/v3/profiles/{id}")
Profile findById(@PathParam("id") String id);
@GET
@Retry(maxRetries = 2)
@Path("/v3/profiles/{id}")
Uni<Profile> findById(@PathParam("id") String id);

@GET
@Retry(maxRetries = 2)
@Path("/avatar/{id}")
String findAvatarUrl(@PathParam("id") String id);
@GET
@Retry(maxRetries = 2)
@Path("/avatar/{id}")
Uni<String> findAvatarUrl(@PathParam("id") String id);

}
3 changes: 3 additions & 0 deletions client/src/main/resources/graphql/find-image.graphql
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
query findImage($id: String!){
componentRichImage(id: $id) {
sys {
id
}
image {
title
description
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.assertj.core.api.Assertions.*;

import java.time.Duration;
import java.util.List;

import jakarta.ws.rs.core.HttpHeaders;
Expand Down Expand Up @@ -31,7 +32,7 @@ void findPageBlogModel() {
.willReturn(ok().withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON).withBodyFile("find-page-blog-model.json")));

// when
var actual = client.findPageBlogModel();
var actual = client.findPageBlogModel().await().atMost(Duration.ofSeconds(1));

// then
assertThat(actual.getFields()).usingRecursiveFieldByFieldElementComparator()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.assertj.core.api.Assertions.assertThat;

import java.time.Duration;
import java.util.Set;

@QuarkusTest
Expand All @@ -32,10 +33,10 @@ void findBlogPost() {
.willReturn(ok().withBodyFile("find-blog-posts.json")));

// when
var actual = client.findBlogPost("slug");
var actual = client.findBlogPost("slug").await().atMost(Duration.ofSeconds(1));

// then
assertThat(actual).isPresent();
assertThat(actual).isNotNull();
}

@Test
Expand All @@ -46,10 +47,10 @@ void findBlogPost_NotFound() {
.willReturn(ok().withBodyFile("find-blog-posts-not-found.json")));

// when
var actual = client.findBlogPost("slug");
var actual = client.findBlogPost("slug").await().atMost(Duration.ofSeconds(1));

// then
assertThat(actual).isEmpty();
assertThat(actual).isNull();
}

@Test
Expand All @@ -64,7 +65,7 @@ void findBlogPosts() {
.willReturn(ok().withBodyFile("find-blog-posts.json")));

// when
var actual = client.findBlogPosts(pagination, tags);
var actual = client.findBlogPosts(pagination, tags).await().atMost(Duration.ofSeconds(1));

// then
assertThat(actual.getItems()).isNotEmpty();
Expand All @@ -78,7 +79,7 @@ void findRecentBlogPosts() {
.willReturn(ok().withBodyFile("find-recent-blog-posts.json")));

// when
var actual = client.findRecentBlogPosts();
var actual = client.findRecentBlogPosts().await().atMost(Duration.ofSeconds(1));

// then
assertThat(actual.getItems()).isNotEmpty();
Expand All @@ -92,11 +93,10 @@ void findImage() {
.willReturn(ok().withBodyFile("find-image.json")));

// when
var actual = client.findImage("id");
var actual = client.findImage("id").await().atMost(Duration.ofSeconds(1));

// then
assertThat(actual).isPresent()
.get()
assertThat(actual)
.usingRecursiveComparison()
.isEqualTo(ComponentRichImage.builder()
.fullWidth(true)
Expand All @@ -118,10 +118,10 @@ void findImage_NotFound() {
.willReturn(ok().withBodyFile("find-image-not-found.json")));

// when
var actual = client.findImage("id");
var actual = client.findImage("id").await().atMost(Duration.ofSeconds(1));

// then
assertThat(actual).isEmpty();
assertThat(actual).isNull();
}

}
Loading

0 comments on commit d15b6c8

Please sign in to comment.