Skip to content

Commit

Permalink
Attempt to autowire GraphQL clients in test mode
Browse files Browse the repository at this point in the history
  • Loading branch information
jmartisk committed Jul 28, 2022
1 parent 80304e4 commit 010af60
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 3 deletions.
5 changes: 5 additions & 0 deletions docs/src/main/asciidoc/smallrye-graphql-client.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,11 @@ or move this over to the configuration file, `application.properties`:
quarkus.smallrye-graphql-client.star-wars-typesafe.url=https://swapi-graphql.netlify.app/.netlify/functions/index
----

NOTE: During *tests only*, the URL is an optional property, and if it's not specified, Quarkus will assume
that the target of the client is the application that is being tested (typically, `http://localhost:8081/graphql`).
This is useful if your application contains a GraphQL server-side API as well as a GraphQL client that is used for
testing the API.

`star-wars-typesafe` is the name of the configured client instance, and corresponds to the `configKey`
in the `@GraphQLClientApi` annotation. If you don't want to specify a custom name, you can leave
out the `configKey`, and then refer to it by using the fully qualified name of the interface.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,17 +140,29 @@ void setTypesafeApiClasses(BeanArchiveIndexBuildItem index,
*/
@BuildStep
@Record(RUNTIME_INIT)
void shortNamesToQualifiedNames(BuildProducer<SyntheticBeanBuildItem> syntheticBeans,
void initializeClientSupport(BuildProducer<SyntheticBeanBuildItem> syntheticBeans,
SmallRyeGraphQLClientRecorder recorder,
GraphQLClientsConfig quarkusConfig,
BeanArchiveIndexBuildItem index) {
// to store config keys of all clients found in the application code
List<String> knownConfigKeys = new ArrayList<>();

Map<String, String> shortNamesToQualifiedNames = new HashMap<>();
for (AnnotationInstance annotation : index.getIndex().getAnnotations(GRAPHQL_CLIENT_API)) {
ClassInfo clazz = annotation.target().asClass();
shortNamesToQualifiedNames.put(clazz.name().withoutPackagePrefix(), clazz.name().toString());
knownConfigKeys.add(clazz.name().toString());
}

for (AnnotationInstance annotation : index.getIndex().getAnnotations(GRAPHQL_CLIENT)) {
String configKey = annotation.value().asString();
if (configKey == null) {
configKey = "default";
}
knownConfigKeys.add(configKey);
}

RuntimeValue<GraphQLClientSupport> support = recorder.clientSupport(shortNamesToQualifiedNames);
RuntimeValue<GraphQLClientSupport> support = recorder.clientSupport(shortNamesToQualifiedNames, knownConfigKeys);

DotName supportClassName = DotName.createSimple(GraphQLClientSupport.class.getName());
SyntheticBeanBuildItem bean = SyntheticBeanBuildItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
import javax.inject.Inject;
import javax.inject.Singleton;

import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
import org.jboss.logging.Logger;

import io.quarkus.runtime.LaunchMode;
import io.smallrye.graphql.client.impl.GraphQLClientConfiguration;
import io.smallrye.graphql.client.impl.GraphQLClientsConfiguration;

Expand All @@ -21,6 +26,8 @@
@Singleton
public class GraphQLClientConfigurationMergerBean {

private final Logger logger = Logger.getLogger(GraphQLClientConfigurationMergerBean.class);

GraphQLClientsConfiguration upstreamConfigs;

@Inject
Expand Down Expand Up @@ -54,6 +61,32 @@ void enhanceGraphQLConfiguration() {
}
}

// allow automatically wiring client to the local server instance in test mode
if (LaunchMode.current() == LaunchMode.TEST) {
String testUrl = null;
for (String configKey : support.getKnownConfigKeys()) {
GraphQLClientConfiguration config = upstreamConfigs.getClient(configKey);
if (config.getUrl() == null) {
if (testUrl == null) {
testUrl = getTestingServerUrl();
}
logger.info("Automatically wiring the URL of GraphQL client named " + configKey + " to " + testUrl
+ ". If this is incorrect, " +
"please set it manually using the quarkus.smallrye-graphql-client." + maybeWithQuotes(configKey)
+ ".url property. Also note that" +
" this autowiring is only supported during tests.");
config.setUrl(testUrl);
}
}
}
}

private String maybeWithQuotes(String key) {
if (key.contains(".")) {
return "\"" + key + "\"";
} else {
return key;
}
}

// translates a Quarkus `GraphQLClientConfig` configuration object to `GraphQLClientConfiguration` which is understood
Expand All @@ -80,6 +113,13 @@ private GraphQLClientConfiguration toSmallRyeNativeConfiguration(GraphQLClientCo
return transformed;
}

private String getTestingServerUrl() {
Config config = ConfigProvider.getConfig();
// the client extension doesn't have dependencies on neither the server extension nor quarkus-vertx-http, so guessing
// is somewhat limited
return "http://localhost:" + config.getOptionalValue("quarkus.http.test-port", int.class).orElse(8081) + "/graphql";
}

public void nothing() {
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.smallrye.graphql.client.runtime;

import java.util.List;
import java.util.Map;

/**
Expand All @@ -14,11 +15,26 @@ public class GraphQLClientSupport {
*/
private Map<String, String> shortNamesToQualifiedNamesMapping;

/**
* All config keys of clients found in the application. The reason for having this is that in TEST mode,
* if a config key is used but doesn't have any associated configuration, we can automatically generate a configuration
* containing a guess of the target URL.
*/
private List<String> knownConfigKeys;

public Map<String, String> getShortNamesToQualifiedNamesMapping() {
return shortNamesToQualifiedNamesMapping;
}

public void setShortNamesToQualifiedNamesMapping(Map<String, String> shortNamesToQualifiedNamesMapping) {
this.shortNamesToQualifiedNamesMapping = shortNamesToQualifiedNamesMapping;
}

public void setKnownConfigKeys(List<String> knownConfigKeys) {
this.knownConfigKeys = knownConfigKeys;
}

public List<String> getKnownConfigKeys() {
return knownConfigKeys;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ public void setTypesafeApiClasses(List<String> apiClassNames) {
configBean.addTypesafeClientApis(classes);
}

public RuntimeValue<GraphQLClientSupport> clientSupport(Map<String, String> shortNamesToQualifiedNames) {
public RuntimeValue<GraphQLClientSupport> clientSupport(Map<String, String> shortNamesToQualifiedNames,
List<String> knownConfigKeys) {
GraphQLClientSupport support = new GraphQLClientSupport();
support.setShortNamesToQualifiedNamesMapping(shortNamesToQualifiedNames);
support.setKnownConfigKeys(knownConfigKeys);
return new RuntimeValue<>(support);
}

Expand Down

0 comments on commit 010af60

Please sign in to comment.