Skip to content

Commit 6c1c53f

Browse files
committed
Add new docs version
1 parent 7f7eb51 commit 6c1c53f

File tree

12 files changed

+2013
-0
lines changed

12 files changed

+2013
-0
lines changed
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
---
2+
id: version-4.0.0-alpha.2-client-customization
3+
title: Client Customization
4+
original_id: client-customization
5+
---
6+
7+
## Ktor HTTP Client Customization
8+
9+
`GraphQLKtorClient` is a thin wrapper on top of [Ktor HTTP Client](https://ktor.io/clients/index.html) and supports fully
10+
asynchronous non-blocking communication. It is highly customizable and can be configured with any supported Ktor HTTP
11+
[engine](https://ktor.io/clients/http-client/engines.html) and [features](https://ktor.io/clients/http-client/features.html).
12+
13+
`GraphQLKtorClient` uses the Ktor HTTP Client to execute the underlying queries. Clients can be customized with different
14+
engines (defaults to Coroutine-based IO) and HTTP client features. Custom configurations can be applied through Ktor DSL
15+
style builders.
16+
17+
See [Ktor HTTP Client documentation](https://ktor.io/clients/index.html) for additional details.
18+
19+
### Global Client Customization
20+
21+
A single instance of `GraphQLKtorClient` can be used to handle many GraphQL operations. You can specify a target engine factory and
22+
configure it through the corresponding [HttpClientConfig](https://api.ktor.io/1.3.2/io.ktor.client/-http-client-config/index.html).
23+
Ktor also provides a number of [standard HTTP features](https://ktor.io/clients/http-client/features.html) and
24+
allows you to easily create custom ones that can be configured globally.
25+
26+
The below example configures a new `GraphQLKtorClient` to use the `OkHttp` engine with custom timeouts, adds a default `X-MY-API-KEY`
27+
header to all requests, and enables basic logging of the requests.
28+
29+
```kotlin
30+
val client = GraphQLKtorClient(
31+
url = URL("http://localhost:8080/graphql"),
32+
engineFactory = OkHttp
33+
) {
34+
engine {
35+
config {
36+
connectTimeout(10, TimeUnit.SECONDS)
37+
readTimeout(60, TimeUnit.SECONDS)
38+
writeTimeout(60, TimeUnit.SECONDS)
39+
}
40+
}
41+
defaultRequest {
42+
header("X-MY-API-KEY", "someSecretApiKey")
43+
}
44+
install(Logging) {
45+
logger = Logger.DEFAULT
46+
level = LogLevel.INFO
47+
}
48+
}
49+
```
50+
51+
### Per Request Customization
52+
53+
In order to be able to customize individual GraphQL requests you need to configure GraphQL Kotlin plugin to generate Ktor
54+
specific client code. See [Gradle](https://expediagroup.github.io/graphql-kotlin/docs/plugins/gradle-plugin) and [Maven](https://expediagroup.github.io/graphql-kotlin/docs/plugins/maven-plugin)
55+
plugin documentation for additional details.
56+
57+
Individual GraphQL requests can be customized through [HttpRequestBuilder](https://api.ktor.io/1.3.2/io.ktor.client.request/-http-request-builder/).
58+
You can use this mechanism to specify custom headers, update target url to include custom query parameters, configure
59+
attributes that can be accessed from the pipeline features as well specify timeouts per request.
60+
61+
```kotlin
62+
val helloWorldQuery = HelloWorldQuery(client)
63+
val result = helloWorldQuery.execute(variables = HelloWorldQuery.Variables(name = null)) {
64+
header("X-B3-TraceId", "0123456789abcdef")
65+
}
66+
```
67+
68+
## Spring WebClient Customization
69+
70+
`GraphQLWebClient` is a thin wrapper on top of [Spring WebClient](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/function/client/WebClient.html)
71+
that relies on Reactor Netty for fully asynchronous non-blocking communications. If you want to use Jetty instead you will
72+
need to exclude provided `io.projectreactor.netty:reactor-netty` dependency and instead add `org.eclipse.jetty:jetty-reactive-httpclient`
73+
dependency.
74+
75+
### Global Client Customization
76+
77+
A single instance of `GraphQLWebClient` can be used to handle many GraphQL operations and you can customize it by providing
78+
a custom instance of `WebClient.Builder`. See [Spring documentation](https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-webclient-customization)
79+
for additional details.
80+
81+
Example below configures `GraphQLWebClient` with custom timeouts and adds a default `X-MY-API-KEY` header to all requests.
82+
83+
```kotlin
84+
val httpClient: HttpClient = HttpClient.create()
85+
.tcpConfiguration { client ->
86+
client.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000)
87+
.doOnConnected { conn ->
88+
conn.addHandlerLast(ReadTimeoutHandler(60_000, TimeUnit.MILLISECONDS))
89+
conn.addHandlerLast(WriteTimeoutHandler(60_000, TimeUnit.MILLISECONDS))
90+
}
91+
}
92+
val connector: ClientHttpConnector = ReactorClientHttpConnector(httpClient.wiretap(true))
93+
val webClientBuilder = WebClient.builder()
94+
.clientConnector(connector)
95+
.defaultHeader("X-MY-API-KEY", "someSecretApiKey")
96+
97+
val client = GraphQLWebClient(
98+
url = "http://localhost:8080/graphql",
99+
builder = webClientBuilder
100+
)
101+
```
102+
103+
### Per Request Customization
104+
105+
In order to be able to customize individual GraphQL requests you need to configure GraphQL Kotlin plugin to generate Spring
106+
WebClient specific client code. See [Gradle](https://expediagroup.github.io/graphql-kotlin/docs/plugins/gradle-plugin)
107+
and [Maven](https://expediagroup.github.io/graphql-kotlin/docs/plugins/maven-plugin) plugin documentation for additional
108+
details.
109+
110+
Individual GraphQL requests can be customized by providing `WebClient.RequestBodyUriSpec` lambda. You can use this mechanism
111+
to specify custom headers or include custom attributes or query parameters.
112+
113+
```kotlin
114+
val helloWorldQuery = HelloWorldQuery(client)
115+
val result = helloWorldQuery.execute(variables = HelloWorldQuery.Variables(name = null)) {
116+
header("X-B3-TraceId", "0123456789abcdef")
117+
}
118+
```
119+
120+
## Custom GraphQL Client
121+
122+
GraphQL Kotlin libraries provide generic a `GraphQLClient` interface as well as Ktor HTTP Client and Spring WebClient based
123+
reference implementations. Both `GraphQLKtorClient` and `GraphQLWebClient` are open classes which means you can also
124+
extend them to provide some custom `execute` logic.
125+
126+
```kotlin
127+
class CustomGraphQLClient(url: URL) : GraphQLKtorClient<CIOEngineConfig>(url = url, engineFactory = CIO) {
128+
129+
override suspend fun <T> execute(query: String, operationName: String?, variables: Any?, resultType: Class<T>, requestBuilder: HttpRequestBuilder.() -> Unit): GraphQLResponse<T> {
130+
// custom init logic
131+
val result = super.execute(query, operationName, variables, resultType, requestBuilder)
132+
// custom finalize logic
133+
return result
134+
}
135+
}
136+
```
137+
138+
> NOTE: When implementing custom `GraphQLClient` make sure to select proper client type when generating your client code.
139+
> By default, generated client code is targeting generic interface which allows you to use any client implementations. If
140+
> you are using Ktor or Spring WebClient based implementations make sure to select corresponding type as that will provide
141+
> customization options.
142+
143+
## Jackson Customization
144+
145+
`GraphQLClient` relies on Jackson to handle polymorphic types and default enum values. You can specify your own custom
146+
object mapper configured with some additional serialization/deserialization features but due to the necessary logic to
147+
handle the above, currently we don't support other JSON libraries.
148+
149+
```kotlin
150+
val customObjectMapper = jacksonObjectMapper()
151+
val client = GraphQLClient(url = URL("http://localhost:8080/graphql"), mapper = customObjectMapper)
152+
```
153+
154+
## Deprecated Field Usage
155+
156+
Build plugins will automatically fail generation of a client if any of the specified query files are referencing
157+
deprecated fields. This ensures that your clients have to explicitly opt-in into deprecated usage by specifying
158+
`allowDeprecatedFields` configuration option.
159+
160+
## Custom GraphQL Scalars
161+
162+
By default, custom GraphQL scalars are serialized and [type-aliased](https://kotlinlang.org/docs/reference/type-aliases.html)
163+
to a String. GraphQL Kotlin plugins also support custom serialization based on provided configuration.
164+
165+
In order to automatically convert between custom GraphQL `UUID` scalar type and `java.util.UUID`, we first need to create
166+
our custom `ScalarConverter`.
167+
168+
```kotlin
169+
package com.example.client
170+
171+
import com.expediagroup.graphql.client.converter.ScalarConverter
172+
import java.util.UUID
173+
174+
class UUIDScalarConverter : ScalarConverter<UUID> {
175+
override fun toScalar(rawValue: Any): UUID = UUID.fromString(rawValue.toString())
176+
override fun toJson(value: UUID): Any = value.toString()
177+
}
178+
```
179+
180+
And then configure build plugin by specifying
181+
* Custom GraphQL scalar name
182+
* Target class name
183+
* Converter that provides logic to map between GraphQL and Kotlin type
184+
185+
```kotlin
186+
graphql {
187+
packageName = "com.example.generated"
188+
endpoint = "http://localhost:8080/graphql"
189+
converters.put("UUID", ScalarConverterMapping("java.util.UUID", "com.example.UUIDScalarConverter"))
190+
}
191+
```
192+
193+
See [Gradle](../plugins/gradle-plugin.md) and [Maven](../plugins/maven-plugin.md) plugin documentation for additional details.

0 commit comments

Comments
 (0)