|
1 | 1 | package io.kestra.plugin.dbt.cloud;
|
2 | 2 |
|
| 3 | +import com.fasterxml.jackson.databind.DeserializationFeature; |
| 4 | +import com.fasterxml.jackson.databind.ObjectMapper; |
| 5 | +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; |
3 | 6 | import io.kestra.core.exceptions.IllegalVariableEvaluationException;
|
4 | 7 | import io.kestra.core.models.property.Property;
|
5 | 8 | import io.kestra.core.models.tasks.Task;
|
6 |
| -import io.kestra.core.runners.DefaultRunContext; |
7 | 9 | import io.kestra.core.runners.RunContext;
|
8 |
| -import io.micronaut.core.type.Argument; |
9 |
| -import io.micronaut.http.HttpResponse; |
10 |
| -import io.micronaut.http.MediaType; |
11 |
| -import io.micronaut.http.MutableHttpRequest; |
12 |
| -import io.micronaut.http.client.DefaultHttpClientConfiguration; |
13 |
| -import io.micronaut.http.client.HttpClient; |
14 |
| -import io.micronaut.http.client.exceptions.HttpClientResponseException; |
15 |
| -import io.micronaut.http.client.netty.DefaultHttpClient; |
16 |
| -import io.micronaut.http.client.netty.NettyHttpClientFactory; |
17 |
| -import io.micronaut.http.codec.MediaTypeCodecRegistry; |
| 10 | +import io.kestra.core.http.HttpRequest; |
| 11 | +import io.kestra.core.http.HttpResponse; |
| 12 | +import io.kestra.core.http.client.HttpClient; |
| 13 | +import io.kestra.core.http.client.HttpClientException; |
| 14 | +import io.kestra.core.http.client.configurations.HttpConfiguration; |
| 15 | + |
18 | 16 | import io.swagger.v3.oas.annotations.media.Schema;
|
19 | 17 | import lombok.*;
|
20 | 18 | import lombok.experimental.SuperBuilder;
|
21 | 19 |
|
22 |
| -import java.net.MalformedURLException; |
23 |
| -import java.net.URI; |
24 |
| -import java.net.URISyntaxException; |
25 |
| -import java.time.Duration; |
| 20 | +import java.io.IOException; |
| 21 | + |
26 | 22 | import jakarta.validation.constraints.NotNull;
|
27 |
| -import reactor.core.publisher.Mono; |
28 | 23 |
|
29 | 24 | @SuperBuilder
|
30 | 25 | @ToString
|
31 | 26 | @EqualsAndHashCode
|
32 | 27 | @Getter
|
33 | 28 | @NoArgsConstructor
|
34 | 29 | public abstract class AbstractDbtCloud extends Task {
|
35 |
| - @Schema( |
36 |
| - title = "Base url to select the tenant." |
37 |
| - ) |
| 30 | + private static final ObjectMapper MAPPER = new ObjectMapper() |
| 31 | + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) |
| 32 | + .registerModule(new JavaTimeModule()); |
| 33 | + |
| 34 | + @Schema(title = "Base URL to select the tenant.") |
38 | 35 | @NotNull
|
39 | 36 | @Builder.Default
|
40 | 37 | Property<String> baseUrl = Property.of("https://cloud.getdbt.com");
|
41 | 38 |
|
42 |
| - @Schema( |
43 |
| - title = "Numeric ID of the account." |
44 |
| - ) |
| 39 | + @Schema(title = "Numeric ID of the account.") |
45 | 40 | @NotNull
|
46 | 41 | Property<String> accountId;
|
47 | 42 |
|
48 |
| - @Schema( |
49 |
| - title = "API key." |
50 |
| - ) |
| 43 | + @Schema(title = "API key.") |
51 | 44 | @NotNull
|
52 | 45 | Property<String> token;
|
53 | 46 |
|
54 |
| - private static final Duration HTTP_READ_TIMEOUT = Duration.ofSeconds(60); |
55 |
| - private static final NettyHttpClientFactory FACTORY = new NettyHttpClientFactory(); |
| 47 | + @Schema(title = "The HTTP client configuration.") |
| 48 | + HttpConfiguration options; |
56 | 49 |
|
57 |
| - protected HttpClient client(RunContext runContext) throws IllegalVariableEvaluationException, MalformedURLException, URISyntaxException { |
58 |
| - MediaTypeCodecRegistry mediaTypeCodecRegistry = ((DefaultRunContext)runContext).getApplicationContext().getBean(MediaTypeCodecRegistry.class); |
| 50 | + /** |
| 51 | + * Perform an HTTP request using Kestra HttpClient. |
| 52 | + * |
| 53 | + * @param requestBuilder The prepared HTTP request builder. |
| 54 | + * @param responseType The expected response type. |
| 55 | + * @param <RES> The response class. |
| 56 | + * @return HttpResponse of type RES. |
| 57 | + */ |
| 58 | + protected <RES> HttpResponse<RES> request(RunContext runContext, HttpRequest.HttpRequestBuilder requestBuilder, Class<RES> responseType) |
| 59 | + throws HttpClientException, IllegalVariableEvaluationException { |
59 | 60 |
|
60 |
| - var httpConfig = new DefaultHttpClientConfiguration(); |
61 |
| - httpConfig.setMaxContentLength(Integer.MAX_VALUE); |
62 |
| - httpConfig.setReadTimeout(HTTP_READ_TIMEOUT); |
| 61 | + var request = requestBuilder |
| 62 | + .addHeader("Authorization", "Bearer " + runContext.render(this.token).as(String.class).orElseThrow()) |
| 63 | + .addHeader("Content-Type", "application/json") |
| 64 | + .build(); |
63 | 65 |
|
64 |
| - DefaultHttpClient client = (DefaultHttpClient) FACTORY.createClient(URI.create(runContext.render(baseUrl).as(String.class).orElseThrow()).toURL(), httpConfig); |
65 |
| - client.setMediaTypeCodecRegistry(mediaTypeCodecRegistry); |
| 66 | + try (HttpClient client = new HttpClient(runContext, options)) { |
| 67 | + HttpResponse<String> response = client.request(request, String.class); |
66 | 68 |
|
67 |
| - return client; |
68 |
| - } |
69 |
| - |
70 |
| - protected <REQ, RES> HttpResponse<RES> request(RunContext runContext, |
71 |
| - MutableHttpRequest<REQ> request, |
72 |
| - Argument<RES> argument) throws HttpClientResponseException { |
73 |
| - return request(runContext, request, argument, null); |
74 |
| - } |
75 |
| - protected <REQ, RES> HttpResponse<RES> request(RunContext runContext, |
76 |
| - MutableHttpRequest<REQ> request, |
77 |
| - Argument<RES> argument, |
78 |
| - Duration timeout) throws HttpClientResponseException { |
79 |
| - try { |
80 |
| - request = request |
81 |
| - .bearerAuth(runContext.render(this.token).as(String.class).orElseThrow()) |
82 |
| - .contentType(MediaType.APPLICATION_JSON); |
| 69 | + RES parsedResponse = MAPPER.readValue(response.getBody(), responseType); |
| 70 | + return HttpResponse.<RES>builder() |
| 71 | + .request(request) |
| 72 | + .body(parsedResponse) |
| 73 | + .headers(response.getHeaders()) |
| 74 | + .status(response.getStatus()) |
| 75 | + .build(); |
83 | 76 |
|
84 |
| - try (HttpClient client = this.client(runContext)) { |
85 |
| - Mono<HttpResponse<RES>> mono = Mono.from(client.exchange(request, argument)); |
86 |
| - return timeout != null ? mono.block(timeout) : mono.block(); |
87 |
| - } |
88 |
| - } catch (HttpClientResponseException e) { |
89 |
| - throw new HttpClientResponseException( |
90 |
| - "Request failed '" + e.getStatus().getCode() + "' and body '" + e.getResponse().getBody(String.class).orElse("null") + "'", |
91 |
| - e, |
92 |
| - e.getResponse() |
93 |
| - ); |
94 |
| - } catch (IllegalVariableEvaluationException | MalformedURLException | URISyntaxException e) { |
95 |
| - throw new RuntimeException(e); |
| 77 | + } catch (IOException e) { |
| 78 | + throw new RuntimeException("Error executing HTTP request", e); |
96 | 79 | }
|
97 | 80 | }
|
98 | 81 | }
|
0 commit comments