Clients
May 4, 2021 ยท View on GitHub
Misk provides configurable HTTP clients built on top of OkHttp and Retrofit, and gRPC clients built on top of Wire.
HTTP Clients
Config
Set up a Config object (and use MiskConfig.load to load config from a YAML file):
data class MyServiceConfig(
val http_clients: HttpClientsConfig,
// ...
) : Config
In the configuration YAML, specify the target service's address:
http_clients:
...
endpoints:
...
greeter: { url: "https://hello.example.com" }
Create an OkHttpClient
Use HttpClientModule:
class MyClientModule : KAbstractModule() {
override fun configure() {
install(HttpClientModule(
// Corresponds to the YAML config. Requires a bound HttpClientsConfig
name = "greeter",
// Optional annotation to define how you inject your client dependency
annotation = Names.named("greeterHttp")
))
}
}
This binds an OkHttpClient that you can inject:
class MyClient @Inject constructor(@Named("greeterHttp") val client: OkHttpClient) {
fun callGreeter() {
val response = client.newCall(
Request.Builder()
.url("http://localhost:8080/hello")
.build()
).execute()
}
}
Create typed clients with Retrofit
First, create a Retrofit interface. See the Retrofit docs for more details.
interface GreeterApi {
@POST("/hello")
@Headers(value = ["accept: application/json"])
fun hello(
@Body request: HelloRequest
): Call<HelloResponse>
}
Next, install a TypedHttpClientModule with this interface.
class HelloClientModule : KAbstractModule() {
override fun configure() {
install(
TypedHttpClientModule(
GreeterApi::class,
// Corresponds to the YAML config. Requires a bound HttpClientsConfig
name = "greeter",
// Optional annotation to define how you inject your client dependency
annotation = Names.named("greeterApi")
)
)
}
}
Now you can inject an implementation of this client:
@Singleton class MyApiClient @Inject constructor(
@Named("greeterApi") private val api: GreeterApi
) {
fun hello(message: String): String {
val response = api.hello(
HelloRequest(
message = message
)
).execute()
}
}
gRPC Clients
First, include the auto-generated gRPC client code at the caller module using the Wire Gradle plugin.
plugins {
id("com.squareup.wire")
}
wire {
sourcePath {
srcDir("src/main/proto")
}
// Generate Kotlin for the gRPC client API.
kotlin {
// Set this to false if you're generating client and server interfaces in one module
exclusive = false
includes ("squareup.cash.hello.GreeterService")
rpcRole = "client"
}
java {
}
}
Next, bind your client in code in a similar fashion to an HTTP client. Set up client configuration,
as described in Config. Then, bind a GrpcClientModule:
class GreeterClientModule : KAbstractModule() {
override fun configure() {
install(GrpcClientModule.create<GreeterServiceClient, GrpcGreeterServiceClient>(
// Corresponds to the YAML config. Requires a bound HttpClientsConfig
name = "greeter",
// Optional annotation to define how you inject your client dependency
annotation = Names.named("greeterGrpc")
))
}
}
With this all setup, you can now inject your client in source code and connect via gRPC:
internal class GrpcGreeterServiceClient @Inject internal constructor(
@Named("greeterGrpc") private val greeterGrpc: GreeterServiceClient
) {
fun get(message: String) {
val response = greeterGrpc.Hello().executeBlocking(HelloRequest(message))
// ... do something with the response here
}
}