0
# Http4s Ember Client
1
2
Http4s Ember Client is a high-performance HTTP client implementation for the http4s library, built on the ember networking library. It provides connection pooling, HTTP/2 support, cross-platform compatibility (JVM, JavaScript, Native), and comprehensive TLS configuration options.
3
4
## Package Information
5
6
- **Package Name**: http4s-ember-client_3
7
- **Package Type**: maven
8
- **Language**: Scala
9
- **Installation**: Add to your `build.sbt`:
10
```scala
11
libraryDependencies += "org.http4s" %% "http4s-ember-client" % "0.23.30"
12
```
13
14
## Core Imports
15
16
```scala
17
import org.http4s.ember.client.EmberClientBuilder
18
import org.http4s.ember.client.EmberClient
19
import cats.effect.IO
20
import org.http4s.client.Client
21
```
22
23
## Basic Usage
24
25
```scala
26
import org.http4s.ember.client.EmberClientBuilder
27
import cats.effect.IO
28
import org.http4s._
29
30
// Create a client with default settings
31
EmberClientBuilder.default[IO].build.use { client =>
32
// Make HTTP requests
33
val request = Request[IO](Method.GET, uri"https://api.example.com/users")
34
client.expect[String](request)
35
}
36
37
// Configure the client
38
EmberClientBuilder.default[IO]
39
.withMaxTotal(200)
40
.withTimeout(30.seconds)
41
.withHttp2
42
.build
43
.use { client =>
44
// Use configured client
45
}
46
```
47
48
## Architecture
49
50
The ember client is built around several key components:
51
52
- **EmberClientBuilder**: Fluent configuration API for setting up client parameters
53
- **EmberClient**: The main client implementation with connection pooling
54
- **Connection Pool**: Automatic connection reuse and management with configurable limits
55
- **Cross-Platform Support**: Single API that works on JVM, JavaScript, and Native platforms
56
- **HTTP/2 Support**: Optional HTTP/2 with server push promise handling
57
- **TLS Integration**: Full TLS/SSL support with endpoint verification
58
59
## Capabilities
60
61
### Client Builder
62
63
Configuration and creation of HTTP clients with comprehensive customization options.
64
65
```scala { .api }
66
/**
67
* Builder for configuring EmberClient instances with fluent API
68
*/
69
final class EmberClientBuilder[F[_]: Async: Network] private (
70
// Internal configuration fields omitted
71
) {
72
73
/** Create the configured HTTP client */
74
def build: Resource[F, Client[F]]
75
76
/** Set custom TLS context */
77
def withTLSContext(tlsContext: TLSContext[F]): EmberClientBuilder[F]
78
79
/** Use system default TLS context */
80
def withoutTLSContext: EmberClientBuilder[F]
81
82
/** Set socket group for connections */
83
def withSocketGroup(sg: SocketGroup[F]): EmberClientBuilder[F]
84
85
/** Set total maximum connections in pool */
86
def withMaxTotal(maxTotal: Int): EmberClientBuilder[F]
87
88
/** Set maximum connections per request key */
89
def withMaxPerKey(maxPerKey: RequestKey => Int): EmberClientBuilder[F]
90
91
/** Set idle timeout for pooled connections */
92
def withIdleTimeInPool(idleTimeInPool: Duration): EmberClientBuilder[F]
93
94
/** Set idle timeout on individual connections */
95
def withIdleConnectionTime(idleConnectionTime: Duration): EmberClientBuilder[F]
96
97
/** Set logger for client operations */
98
def withLogger(logger: Logger[F]): EmberClientBuilder[F]
99
100
/** Set chunk size for reading from sockets */
101
def withChunkSize(chunkSize: Int): EmberClientBuilder[F]
102
103
/** Set maximum response header size */
104
def withMaxResponseHeaderSize(maxResponseHeaderSize: Int): EmberClientBuilder[F]
105
106
/** Set header receive timeout */
107
def withTimeout(timeout: Duration): EmberClientBuilder[F]
108
109
/** Set additional socket options */
110
def withAdditionalSocketOptions(additionalSocketOptions: List[SocketOption]): EmberClientBuilder[F]
111
112
/** Set default User-Agent header */
113
def withUserAgent(userAgent: `User-Agent`): EmberClientBuilder[F]
114
115
/** Clear default User-Agent header */
116
def withoutUserAgent: EmberClientBuilder[F]
117
118
/** Enable/disable endpoint authentication verification */
119
def withCheckEndpointAuthentication(checkEndpointIdentification: Boolean): EmberClientBuilder[F]
120
121
/** Disable endpoint authentication verification */
122
def withoutCheckEndpointAuthentication: EmberClientBuilder[F]
123
124
/** Enable/disable Server Name Indication */
125
def withServerNameIndication(serverNameIndication: Boolean): EmberClientBuilder[F]
126
127
/** Disable Server Name Indication */
128
def withoutServerNameIndication: EmberClientBuilder[F]
129
130
/** Set retry policy for failed requests */
131
def withRetryPolicy(retryPolicy: RetryPolicy[F]): EmberClientBuilder[F]
132
133
/** Enable Unix socket support */
134
def withUnixSockets(unixSockets: UnixSockets[F]): EmberClientBuilder[F]
135
136
/** Enable HTTP/2 support */
137
def withHttp2: EmberClientBuilder[F]
138
139
/** Disable HTTP/2 support */
140
def withoutHttp2: EmberClientBuilder[F]
141
142
/** Set HTTP/2 push promise handler */
143
def withPushPromiseSupport(
144
f: (Request[fs2.Pure], F[Response[F]]) => F[Outcome[F, Throwable, Unit]]
145
): EmberClientBuilder[F]
146
147
/** Disable HTTP/2 push promise support */
148
def withoutPushPromiseSupport: EmberClientBuilder[F]
149
}
150
151
/**
152
* Factory methods for creating EmberClientBuilder instances
153
*/
154
object EmberClientBuilder {
155
/** Create builder with default configuration */
156
def default[F[_]: Async: Network]: EmberClientBuilder[F]
157
158
/** Create builder with default configuration (deprecated) */
159
@deprecated("Use default[F[_]: Async: Network] instead", "0.23.16")
160
def default[F[_]](async: Async[F]): EmberClientBuilder[F]
161
}
162
```
163
164
**Usage Examples:**
165
166
```scala
167
import org.http4s.ember.client.EmberClientBuilder
168
import cats.effect.IO
169
import scala.concurrent.duration._
170
171
// Basic client with defaults
172
val basicClient = EmberClientBuilder.default[IO].build
173
174
// Custom configuration
175
val customClient = EmberClientBuilder.default[IO]
176
.withMaxTotal(500)
177
.withMaxPerKey(_ => 50)
178
.withTimeout(45.seconds)
179
.withIdleConnectionTime(60.seconds)
180
.withChunkSize(64 * 1024)
181
.build
182
183
// HTTP/2 enabled client
184
val http2Client = EmberClientBuilder.default[IO]
185
.withHttp2
186
.withPushPromiseSupport { case (request, response) =>
187
// Handle server push promises
188
IO.pure(cats.effect.Outcome.Succeeded(IO.unit))
189
}
190
.build
191
192
// TLS configured client
193
val tlsClient = EmberClientBuilder.default[IO]
194
.withCheckEndpointAuthentication(true)
195
.withServerNameIndication(true)
196
.build
197
198
// Unix socket client
199
import fs2.io.net.unixsocket.UnixSockets
200
val unixClient = EmberClientBuilder.default[IO]
201
.withUnixSockets(UnixSockets.forAsync[IO])
202
.build
203
```
204
205
### HTTP Client Operations
206
207
Main HTTP client functionality for executing requests with connection pooling and state monitoring.
208
209
```scala { .api }
210
/**
211
* HTTP client implementation with connection pooling
212
*/
213
final class EmberClient[F[_]] private[client] (
214
private val client: Client[F],
215
private val pool: KeyPool[F, RequestKey, EmberConnection[F]]
216
)(implicit F: MonadCancelThrow[F]) extends DefaultClient[F] {
217
218
/** Execute HTTP request and return response resource */
219
def run(req: Request[F]): Resource[F, Response[F]]
220
221
/** Get current connection pool state */
222
def state: F[(Int, Map[RequestKey, Int])]
223
224
/** Default error handling for unsuccessful responses */
225
override def defaultOnError(req: Request[F])(resp: Response[F])(implicit G: Applicative[F]): F[Throwable]
226
}
227
```
228
229
**Usage Examples:**
230
231
```scala
232
import org.http4s._
233
import org.http4s.ember.client.EmberClientBuilder
234
import cats.effect.IO
235
236
// Basic request execution
237
EmberClientBuilder.default[IO].build.use { client =>
238
val request = Request[IO](Method.GET, uri"https://api.github.com/users/octocat")
239
240
// Get response as Resource
241
client.run(request).use { response =>
242
response.body.compile.toVector.map(bytes => new String(bytes.toArray))
243
}
244
245
// Or use convenience methods
246
client.expect[String](request)
247
}
248
249
// Monitor connection pool state
250
EmberClientBuilder.default[IO].build.use { client =>
251
for {
252
_ <- client.expect[String](Request[IO](Method.GET, uri"https://example.com"))
253
(totalConns, perKeyConns) <- client.state
254
_ <- IO.println(s"Total connections: $totalConns")
255
_ <- IO.println(s"Per-key connections: $perKeyConns")
256
} yield ()
257
}
258
259
// Handle different response types
260
EmberClientBuilder.default[IO].build.use { client =>
261
val jsonRequest = Request[IO](Method.GET, uri"https://api.github.com/users/octocat")
262
.withHeaders(Header.Raw(ci"Accept", "application/json"))
263
264
// Expect JSON response
265
import io.circe.Json
266
import org.http4s.circe._
267
client.expect[Json](jsonRequest)
268
}
269
```
270
271
## Default Configuration
272
273
### Connection Pool Settings
274
- **maxTotal**: 100 - Maximum total connections across all request keys
275
- **maxPerKey**: 100 - Maximum connections per individual request key
276
- **idleTimeInPool**: 30 seconds - How long connections can remain idle in the pool
277
278
### Network Settings
279
- **chunkSize**: 32KB (32,768 bytes) - Size of chunks when reading from sockets
280
- **maxResponseHeaderSize**: 4KB (4,096 bytes) - Maximum size for response headers
281
- **timeout**: 45 seconds - Maximum time to wait for response headers
282
- **idleConnectionTime**: 60 seconds - Idle timeout for individual connections
283
284
### Security Settings
285
- **checkEndpointIdentification**: true - Verify server identity against certificate
286
- **serverNameIndication**: true - Enable SNI for proper certificate selection
287
- **tlsContext**: System default SSL context
288
289
### Protocol Settings
290
- **enableHttp2**: false - HTTP/2 support disabled by default
291
- **pushPromiseSupport**: None - Server push promises disabled by default
292
- **userAgent**: "http4s-ember/{version}" - Default User-Agent header
293
294
### Retry Settings
295
- **retryPolicy**: RetryUntilFresh - Default retry strategy for failed requests
296
297
## Platform Support
298
299
### JVM Platform
300
- Full feature support including Unix sockets
301
- Uses Slf4j logging by default
302
- Supports all TLS features and socket options
303
304
### JavaScript Platform
305
- Available since version 0.23.5
306
- Uses NoOp logging by default
307
- HTTP/2 and TLS support available
308
309
### Native Platform
310
- Available since version 0.23.16
311
- Uses NoOp logging by default
312
- Full networking feature support (excluding Unix sockets)
313
314
## Types
315
316
```scala { .api }
317
// From cats-effect and fs2
318
import cats.effect.{Async, Resource, MonadCancelThrow}
319
import fs2.io.net.{Network, SocketGroup, SocketOption, TLSContext}
320
import fs2.io.net.unixsocket.{UnixSockets, UnixSocketAddress}
321
322
// From http4s
323
import org.http4s.{Request, Response, Method, Uri}
324
import org.http4s.client.{Client, RequestKey, RetryPolicy}
325
import org.http4s.headers.`User-Agent`
326
327
// From log4cats
328
import org.typelevel.log4cats.Logger
329
330
// From keypool
331
import org.typelevel.keypool.KeyPool
332
333
// Scala standard library
334
import scala.concurrent.duration.{Duration, FiniteDuration}
335
336
// Connection pool state: (total connections, connections per request key)
337
type PoolState = (Int, Map[RequestKey, Int])
338
339
// Push promise handler for HTTP/2
340
type PushPromiseHandler[F[_]] = (Request[fs2.Pure], F[Response[F]]) => F[cats.effect.Outcome[F, Throwable, Unit]]
341
```
342
343
## Error Handling
344
345
The ember client provides comprehensive error handling:
346
347
```scala
348
import org.http4s.ember.client.EmberClientBuilder
349
import cats.effect.IO
350
import org.http4s._
351
352
EmberClientBuilder.default[IO].build.use { client =>
353
val request = Request[IO](Method.GET, uri"https://httpbin.org/status/404")
354
355
client.run(request).use { response =>
356
if (response.status.isSuccess) {
357
response.body.compile.toVector
358
} else {
359
IO.raiseError(new RuntimeException(s"Request failed: ${response.status}"))
360
}
361
}
362
}
363
```
364
365
Common exceptions:
366
- **UnexpectedStatus**: When server returns non-success status codes
367
- **TimeoutException**: When requests exceed configured timeout
368
- **TLS exceptions**: For certificate verification failures
369
- **Connection exceptions**: For network connectivity issues