Skip to content

Commit d0e4d28

Browse files
committed
Fix #1065 - Add Dynamic URL support
Signed-off-by: Ricardo Zanini <[email protected]>
1 parent c959e67 commit d0e4d28

File tree

13 files changed

+110
-32
lines changed

13 files changed

+110
-32
lines changed

client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/CodegenConfig.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ enum ConfigName {
7777
GENERATE_MODELS("generate-models"),
7878
BEAN_VALIDATION("use-bean-validation"),
7979
SERIALIZABLE_MODEL("serializable-model"),
80-
EQUALS_HASHCODE("equals-hashcode");
80+
EQUALS_HASHCODE("equals-hashcode"),
81+
USE_DYNAMIC_URL("use-dynamic-url");
8182

8283
private final String name;
8384

client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/SpecItemConfig.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.Optional;
44

5+
import io.smallrye.config.WithDefault;
56
import io.smallrye.config.WithName;
67

78
/*
@@ -68,4 +69,14 @@ public interface SpecItemConfig extends CommonItemConfig {
6869
@WithName("serializable-model")
6970
Optional<Boolean> serializableModel();
7071

72+
/**
73+
* Whether to enable Dynamic URLs on APIs methods.
74+
* By enabling this property every method on `RestClients` will be annotated with `io.quarkus.rest.client.reactive.Url`.
75+
*
76+
* @see <a href="https://quarkus.io/version/3.20/guides/rest-client#dynamic-base-urls">Dynamic base URLs</a>
77+
*/
78+
@WithName("use-dynamic-url")
79+
@WithDefault("false")
80+
Optional<Boolean> useDynamicUrl();
81+
7182
}

client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,12 @@ protected void generate(OpenApiGeneratorOptions options) {
339339
OpenApiClientGeneratorWrapper.SUPPORTS_ADDITIONAL_PROPERTIES_AS_ATTRIBUTE,
340340
additionalPropertiesAsAttribute.toString());
341341

342+
getValues(smallRyeConfig, openApiFilePath, CodegenConfig.ConfigName.USE_DYNAMIC_URL, Boolean.class)
343+
.ifPresent(generator::withUseDynamicUrl);
344+
345+
System.out.println("This is the DYNAMIC URL "
346+
+ getValues(smallRyeConfig, openApiFilePath, CodegenConfig.ConfigName.USE_DYNAMIC_URL, Boolean.class));
347+
342348
generator.generate(basePackage);
343349
}
344350

client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ private void setDefaults() {
111111
this.configurator.addAdditionalProperty("verbose", FALSE);
112112
this.configurator.addAdditionalProperty(CodegenConstants.SERIALIZABLE_MODEL, FALSE);
113113
this.configurator.addAdditionalProperty("equals-hashcode", TRUE);
114+
this.configurator.addAdditionalProperty("use-dynamic-url", FALSE);
114115
}
115116

116117
/**
@@ -323,6 +324,11 @@ public OpenApiClientGeneratorWrapper withModelNamePrefix(final String modelNameP
323324
return this;
324325
}
325326

327+
public OpenApiClientGeneratorWrapper withUseDynamicUrl(final Boolean useDynamicUrl) {
328+
this.configurator.addAdditionalProperty("use-dynamic-url", useDynamicUrl);
329+
return this;
330+
}
331+
326332
/**
327333
* Main entrypoint, or where to generate the files based on the given base package.
328334
*

client/deployment/src/main/resources/templates/libraries/microprofile/api.qute

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public interface {classname} {
128128
!}{arg}{#if arg_hasNext}, {/if}{/for}{!
129129
!}{#if op.allParams || op.hasFormParams},{/if}
130130
{/if}
131-
{#if is-resteasy-reactive}
131+
{#if is-resteasy-reactive && use-dynamic-url}
132132
// See https://quarkus.io/version/3.20/guides/rest-client#dynamic-base-urls
133133
@io.quarkus.rest.client.reactive.Url String dynUrl{#if op.allParams || op.hasFormParams},{/if}
134134
{/if}

client/deployment/src/test/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapperTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,10 @@ void verifyAPINormalization() throws Exception {
674674

675675
@Test
676676
void verifyDynamicUrlAnnotation() throws Exception {
677-
List<File> generatedFiles = createGeneratorWrapperReactive("petstore-openapi.json").generate("org.dynamic.url").stream()
677+
List<File> generatedFiles = createGeneratorWrapperReactive("petstore-openapi.json")
678+
.withUseDynamicUrl(true)
679+
.generate("org.dynamic.url")
680+
.stream()
678681
.filter(file -> file.getPath().endsWith("PetApi.java")).toList();
679682

680683
assertThat(generatedFiles).isNotEmpty();

client/integration-tests/bean-validation/src/test/java/io/quarkiverse/openapi/generator/it/BeanValidationTest.java

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import org.openapi.quarkus.bean_validation_true_yaml.model.ValidatedObject;
2828
import org.openapi.quarkus.issue_976_yaml.api.ValidatedEndpointIssue976Api;
2929

30-
import io.quarkus.rest.client.reactive.Url;
3130
import io.quarkus.test.junit.QuarkusTest;
3231

3332
@QuarkusTest
@@ -37,17 +36,12 @@ class BeanValidationTest {
3736
void testValidationAnnotationsAreInPlaceApi() {
3837
Method method = ValidatedEndpointApi.class.getMethods()[0];
3938
Annotation[][] annotationsPerParameter = method.getParameterAnnotations();
39+
Boolean validationAnnotationExists = Arrays.stream(annotationsPerParameter)
40+
.allMatch(annotations -> Arrays.stream(annotations)
41+
.filter(a -> a.annotationType().equals(Valid.class)).toList()
42+
.size() == 1);
4043

41-
boolean allValidExceptUrl = Arrays.stream(annotationsPerParameter)
42-
.allMatch(annotations -> {
43-
boolean hasUrl = Arrays.stream(annotations)
44-
.anyMatch(a -> a.annotationType().equals(Url.class));
45-
boolean hasValid = Arrays.stream(annotations)
46-
.anyMatch(a -> a.annotationType().equals(Valid.class));
47-
return hasUrl || hasValid;
48-
});
49-
50-
assertThat(allValidExceptUrl).isTrue();
44+
assertThat(validationAnnotationExists).isTrue();
5145
}
5246

5347
@Test
@@ -117,24 +111,18 @@ void testValidationAnnotationsAreInPlaceApiIssue976() {
117111

118112
Parameter pathParam = Arrays.stream(method.getParameters())
119113
.filter(p -> p.getName().equals("pathParam"))
120-
.findFirst()
121-
.orElseThrow(() -> new AssertionError("pathParam not found"));
114+
.findFirst().get();
122115

123116
Parameter headerParam = Arrays.stream(method.getParameters())
124117
.filter(p -> p.getName().equals("headerParam"))
125-
.findFirst()
126-
.orElseThrow(() -> new AssertionError("headerParam not found"));
127-
128-
boolean allValidExceptUrl = Arrays.stream(annotationsPerParameter)
129-
.allMatch(annotations -> {
130-
boolean hasUrl = Arrays.stream(annotations)
131-
.anyMatch(a -> a.annotationType().equals(Url.class));
132-
boolean hasValid = Arrays.stream(annotations)
133-
.anyMatch(a -> a.annotationType().equals(Valid.class));
134-
return hasUrl || hasValid;
135-
});
136-
137-
assertThat(allValidExceptUrl).isTrue();
118+
.findFirst().get();
119+
120+
Boolean validationAnnotationExists = Arrays.stream(annotationsPerParameter)
121+
.allMatch(annotations -> Arrays.stream(annotations)
122+
.filter(a -> a.annotationType().equals(Valid.class)).toList()
123+
.size() == 1);
124+
125+
assertThat(validationAnnotationExists).isTrue();
138126

139127
assertThat(pathParam.isAnnotationPresent(Valid.class)).isTrue();
140128
assertThat(pathParam.isAnnotationPresent(NotNull.class)).isTrue();

client/integration-tests/beanparam/src/test/java/io/quarkiverse/openapi/generator/it/BeanParamOpenApiTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ void getRequestReceivesQueryParam() {
3636
TestObjQueryParam model = new TestObjQueryParam();
3737
model.size(42);
3838

39-
ResponseDto responseDto = api.getTest(null, model, true);
39+
ResponseDto responseDto = api.getTest(model, true);
4040
assertThat(responseDto.getMessage()).isEqualTo("Hello");
4141

4242
wireMockServer.verify(getRequestedFor(urlEqualTo("/get?size=42&unpaged=true")));
@@ -48,7 +48,7 @@ void patchRequestReceivesParamsAsBody() {
4848
requestModel.setName("Max");
4949
requestModel.setAge(42);
5050

51-
api.patchTest(null, requestModel);
51+
api.patchTest(requestModel);
5252

5353
wireMockServer.verify(patchRequestedFor(urlEqualTo("/patch"))
5454
.withHeader("Content-Type", equalTo("application/json"))

client/integration-tests/cookie-authentication/src/test/java/io/quarkiverse/openapi/generator/it/CookieAuthenticationTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class CookieAuthenticationTest {
3232

3333
@Test
3434
void apiIsBeingGenerated() {
35-
final Response response = testApi.doTest(null)
35+
final Response response = testApi.doTest()
3636
.await()
3737
.atMost(Duration.ofSeconds(5L));
3838
assertThat(response)

docs/modules/ROOT/pages/client.adoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,11 @@ quarkus.openapi-generator.codegen.spec.my_openapi_yaml.serializable-model=true
199199

200200
include::./includes/equals-hashcode.adoc[leveloffset=+1, opts=optional]
201201

202+
[[dynamic-url]]
203+
== Dynamic base URLs
204+
205+
include::./includes/dynamic-url.adoc[leveloffset=+1, opts=optional]
206+
202207
== Known Limitations
203208

204209
=== Supported Arguments

0 commit comments

Comments
 (0)