This is a proposal to deprecate the current http client interface HttpClient[F[_], Req, Resp] that uses get[Resp], getResource[Resp], post[Resp], etc. Instead, adding a Scala-3 friendly simplified interface SyncClient/AsyncClient that consolidate these legacy methods into a simple one. For example, you can send a http request send(request: HttpMessage.Request): HttpMessage.Response method.
You can test the new interface like this:
import wvlet.airframe.http.Http
// Using Java's standard http client
val client: SyncClient = Http
.client
.withRequestFilter(...)
.withConnectTimeout(...)
.newSyncClient(baseUrl)
// Simple request and receives a raw http response
val r: Response = client.send(Http.GET("/path").withHeader(....))
// Send POST request with JSON body and read the response as an MyObj object
client.readAs[MyObj](Http.POST("/path2").withJson(...))
// Send an object data as the request body, and receive the response as ResponseType object
// JSON/MessagePack data will be transformed internally
val resp: ResponseType = client.call[RequestType, ResponseType](Http.POST("/path3"), requestDataObj)
// When you need to use OkHttp client
import wvlet.airframe.http.okhttp.OkHttp
// The same http interface will be used (WARNING! This is not yet implemented)
val okHttpClient: SyncClient = OkHttp
.client
.withXXX(...) // OkHttp specific configuration
.newSyncClient(baseUrl)
What will be changed
What will not be changed
- Server side interface. Finagle and gRPC servers can be used without any change
The current usage of HttpClient[F[_], Req, Resp] interface
- airframe-okhttp (TD's conductor, td-scala-util, etc.)
- airframe-http-finagle FinagleClient (it's frequently used in test cases)
- airframe-http-recorder (Several test usages)
Hopefully, changing the client initialization and the request/response interface to HttpMessage.Request/Response will work for the migratin.
And unit tests that uses Finagle.client, OkHttpClient, http recorder, etc.
Background: Why does it need to be changed?
Difficulty of Scala 3 Support
The current interface HttpClient[F[_], Req, Resp] has many methods that takes TypeTag, which is no longer available in Scala 3:
airframe-http-recorder implementation is tied to Finagle because it uses Finagle as the backend. But, Finagle will not be migrated to Scala 3 in near future, so we need to find an alternative solution (e.g., implementing Netty4-based server backend)
Supporting multiple HTTP client backends becomes less important
HttpClient[F[_], Res, Resp] design was introduced to support various types of Future types (Scala Future or Twitter Future), http request/response types (Finagle's http Request/Response, OkHttp's Request/Response). Now that airframe-http has the standard HttpMessage.Request/Response classes, supporting different request/response types becomes less important. If you use RPC, directly manipulating http request and response is unnecessary other than for implementing HTTP request filters.
Since Java 9, you can use a standard Java client, which is already supported in https://github.com/wvlet/airframe/blob/master/airframe-http/.jvm/src/main/scala/wvlet/airframe/http/client/JavaClientChannel.scala
This client requires no extra dependency other than Java 9 or later.
Finagle Request are mutable
Finagle's request object is mutable. The new HttpMessage.Request is an immutable object, which is better to avoid unexpected side-effect.
Future Work
AsyncClient is currently using Scala's Future[X] interface, but it's a bit inconvenient that we always need to provide ExecutionContext for Future objects. Instead, having an Rx-based http client interface #2300, which can support Scala.js and gRPC would be ideal.
This is a proposal to deprecate the current http client interface HttpClient[F[_], Req, Resp] that uses get[Resp], getResource[Resp], post[Resp], etc. Instead, adding a Scala-3 friendly simplified interface SyncClient/AsyncClient that consolidate these legacy methods into a simple one. For example, you can send a http request
send(request: HttpMessage.Request): HttpMessage.Responsemethod.You can test the new interface like this:
What will be changed
What will not be changed
The current usage of HttpClient[F[_], Req, Resp] interface
Hopefully, changing the client initialization and the request/response interface to HttpMessage.Request/Response will work for the migratin.
And unit tests that uses Finagle.client, OkHttpClient, http recorder, etc.
Background: Why does it need to be changed?
Difficulty of Scala 3 Support
The current interface HttpClient[F[_], Req, Resp] has many methods that takes TypeTag, which is no longer available in Scala 3:
As a workaround to support Scala 3, HttpClientBase class was added to provide different implementations for Scala 2 and Scala 3.
airframe-http-recorder implementation is tied to Finagle because it uses Finagle as the backend. But, Finagle will not be migrated to Scala 3 in near future, so we need to find an alternative solution (e.g., implementing Netty4-based server backend)
Supporting multiple HTTP client backends becomes less important
HttpClient[F[_], Res, Resp] design was introduced to support various types of Future types (Scala Future or Twitter Future), http request/response types (Finagle's http Request/Response, OkHttp's Request/Response). Now that airframe-http has the standard HttpMessage.Request/Response classes, supporting different request/response types becomes less important. If you use RPC, directly manipulating http request and response is unnecessary other than for implementing HTTP request filters.
Since Java 9, you can use a standard Java client, which is already supported in https://github.com/wvlet/airframe/blob/master/airframe-http/.jvm/src/main/scala/wvlet/airframe/http/client/JavaClientChannel.scala
This client requires no extra dependency other than Java 9 or later.
Finagle Request are mutable
Finagle's request object is mutable. The new HttpMessage.Request is an immutable object, which is better to avoid unexpected side-effect.
Future Work
AsyncClient is currently using Scala's Future[X] interface, but it's a bit inconvenient that we always need to provide ExecutionContext for Future objects. Instead, having an Rx-based http client interface #2300, which can support Scala.js and gRPC would be ideal.