or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

http-abstractions.mdhttp-clients.mdindex.mdmessage-conversion.mdreactive-web.mdweb-binding.mdweb-utilities.md

http-clients.mddocs/

0

# HTTP Clients

1

2

Comprehensive HTTP client support for consuming REST APIs and web services. Spring Web provides both traditional template-based clients (RestTemplate) and modern fluent clients (RestClient), along with configurable client infrastructure.

3

4

## Capabilities

5

6

### RestClient - Modern Fluent API

7

8

Modern synchronous HTTP client with a fluent API design for type-safe and readable HTTP operations.

9

10

```java { .api }

11

/**

12

* Fluent synchronous HTTP client interface

13

*/

14

interface RestClient {

15

// HTTP method specifications

16

RequestHeadersUriSpec<?> get();

17

RequestBodyUriSpec post();

18

RequestBodyUriSpec put();

19

RequestBodyUriSpec patch();

20

RequestHeadersUriSpec<?> delete();

21

RequestHeadersUriSpec<?> head();

22

RequestHeadersUriSpec<?> options();

23

RequestBodyUriSpec method(HttpMethod method);

24

25

// Factory methods

26

static RestClient create();

27

static RestClient create(String baseUrl);

28

static RestClient create(RestTemplate restTemplate);

29

static RestClient.Builder builder();

30

static RestClient.Builder builder(RestTemplate restTemplate);

31

}

32

33

/**

34

* RestClient builder for configuration

35

*/

36

interface RestClient.Builder {

37

RestClient.Builder baseUrl(String baseUrl);

38

RestClient.Builder defaultUriVariables(Map<String, ?> defaultUriVariables);

39

RestClient.Builder defaultHeader(String header, String... values);

40

RestClient.Builder defaultHeaders(Consumer<HttpHeaders> headersConsumer);

41

RestClient.Builder defaultRequest(Consumer<RequestHeadersSpec<?>> defaultRequest);

42

RestClient.Builder requestFactory(ClientHttpRequestFactory requestFactory);

43

RestClient.Builder messageConverters(Consumer<List<HttpMessageConverter<?>>> configurer);

44

RestClient.Builder requestInterceptor(ClientHttpRequestInterceptor interceptor);

45

RestClient.Builder requestInterceptors(Consumer<List<ClientHttpRequestInterceptor>> interceptorsConsumer);

46

RestClient.Builder requestInitializer(ClientHttpRequestInitializer initializer);

47

RestClient.Builder requestInitializers(Consumer<List<ClientHttpRequestInitializer>> initializersConsumer);

48

RestClient.Builder statusHandler(Predicate<HttpStatusCode> statusPredicate, ResponseErrorHandler errorHandler);

49

RestClient.Builder defaultStatusHandler(ResponseErrorHandler errorHandler);

50

RestClient.Builder observationRegistry(ObservationRegistry observationRegistry);

51

RestClient.Builder observationConvention(ClientRequestObservationConvention observationConvention);

52

RestClient build();

53

}

54

55

/**

56

* URI specification for requests without body

57

*/

58

interface RequestHeadersUriSpec<S extends RequestHeadersSpec<S>> extends UriSpec<S> {

59

// Inherited from UriSpec: uri methods

60

}

61

62

/**

63

* URI specification for requests with body

64

*/

65

interface RequestBodyUriSpec extends RequestBodySpec, RequestHeadersUriSpec<RequestBodySpec> {

66

// Combines URI and body specification

67

}

68

69

/**

70

* Headers specification for all request types

71

*/

72

interface RequestHeadersSpec<S extends RequestHeadersSpec<S>> {

73

S header(String headerName, String... headerValues);

74

S headers(Consumer<HttpHeaders> headersConsumer);

75

S accept(MediaType... acceptableMediaTypes);

76

S acceptCharset(Charset... acceptableCharsets);

77

S ifModifiedSince(ZonedDateTime ifModifiedSince);

78

S ifNoneMatch(String... ifNoneMatches);

79

80

// Execute and retrieve response

81

ResponseEntity<Void> retrieve();

82

<T> ResponseEntity<T> retrieve(Class<T> bodyType);

83

<T> ResponseEntity<T> retrieve(ParameterizedTypeReference<T> bodyType);

84

85

// Exchange for full control

86

<T> T exchange(ExchangeFunction<T> exchangeFunction);

87

}

88

89

/**

90

* Body specification for requests with content

91

*/

92

interface RequestBodySpec extends RequestHeadersSpec<RequestBodySpec> {

93

RequestBodySpec contentType(MediaType contentType);

94

RequestBodySpec contentLength(long contentLength);

95

RequestBodySpec body(Object body);

96

<T> RequestBodySpec body(T body, Class<T> bodyType);

97

<T> RequestBodySpec body(T body, ParameterizedTypeReference<T> bodyType);

98

}

99

100

/**

101

* URI specification methods

102

*/

103

interface UriSpec<S extends RequestHeadersSpec<S>> {

104

S uri(String uri, Object... uriVariables);

105

S uri(String uri, Map<String, ?> uriVariables);

106

S uri(URI uri);

107

S uri(Function<UriBuilder, URI> uriFunction);

108

}

109

```

110

111

**Usage Examples:**

112

113

```java

114

// Create RestClient

115

RestClient restClient = RestClient.create("https://api.example.com");

116

117

// Simple GET request

118

String response = restClient.get()

119

.uri("/users/{id}", 123)

120

.retrieve()

121

.body(String.class);

122

123

// POST request with JSON body

124

User user = new User("John", "john@example.com");

125

User createdUser = restClient.post()

126

.uri("/users")

127

.contentType(MediaType.APPLICATION_JSON)

128

.body(user)

129

.retrieve()

130

.body(User.class);

131

132

// GET with custom headers

133

List<User> users = restClient.get()

134

.uri("/users")

135

.header("Authorization", "Bearer token")

136

.accept(MediaType.APPLICATION_JSON)

137

.retrieve()

138

.body(new ParameterizedTypeReference<List<User>>() {});

139

140

// Error handling with exchange

141

String result = restClient.get()

142

.uri("/users/{id}", 404)

143

.exchange((request, response) -> {

144

if (response.getStatusCode().is4xxClientError()) {

145

return "User not found";

146

}

147

return response.bodyTo(String.class);

148

});

149

150

// Builder configuration

151

RestClient configuredClient = RestClient.builder()

152

.baseUrl("https://api.example.com")

153

.defaultHeader("Authorization", "Bearer token")

154

.defaultHeader("User-Agent", "MyApp/1.0")

155

.statusHandler(HttpStatus::is4xxClientError, (request, response) -> {

156

throw new ClientErrorException(response.getStatusCode());

157

})

158

.build();

159

```

160

161

### RestTemplate - Traditional Template API

162

163

Traditional synchronous HTTP client providing template method patterns for HTTP operations.

164

165

```java { .api }

166

/**

167

* Traditional synchronous client to perform HTTP requests

168

*/

169

class RestTemplate extends InterceptingHttpAccessor implements RestOperations {

170

RestTemplate();

171

RestTemplate(ClientHttpRequestFactory requestFactory);

172

RestTemplate(List<HttpMessageConverter<?>> messageConverters);

173

174

// GET operations

175

<T> T getForObject(String url, Class<T> responseType, Object... uriVariables);

176

<T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables);

177

<T> T getForObject(URI url, Class<T> responseType);

178

179

<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables);

180

<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables);

181

<T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType);

182

183

// HEAD operations

184

HttpHeaders headForHeaders(String url, Object... uriVariables);

185

HttpHeaders headForHeaders(String url, Map<String, ?> uriVariables);

186

HttpHeaders headForHeaders(URI url);

187

188

// POST operations

189

<T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables);

190

<T> T postForObject(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables);

191

<T> T postForObject(URI url, Object request, Class<T> responseType);

192

193

<T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables);

194

<T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables);

195

<T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType);

196

197

URI postForLocation(String url, Object request, Object... uriVariables);

198

URI postForLocation(String url, Object request, Map<String, ?> uriVariables);

199

URI postForLocation(URI url, Object request);

200

201

// PUT operations

202

void put(String url, Object request, Object... uriVariables);

203

void put(String url, Object request, Map<String, ?> uriVariables);

204

void put(URI url, Object request);

205

206

// PATCH operations

207

<T> T patchForObject(String url, Object request, Class<T> responseType, Object... uriVariables);

208

<T> T patchForObject(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables);

209

<T> T patchForObject(URI url, Object request, Class<T> responseType);

210

211

// DELETE operations

212

void delete(String url, Object... uriVariables);

213

void delete(String url, Map<String, ?> uriVariables);

214

void delete(URI url);

215

216

// OPTIONS operations

217

Set<HttpMethod> optionsForAllow(String url, Object... uriVariables);

218

Set<HttpMethod> optionsForAllow(String url, Map<String, ?> uriVariables);

219

Set<HttpMethod> optionsForAllow(URI url);

220

221

// Generic exchange operations

222

<T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity,

223

Class<T> responseType, Object... uriVariables);

224

<T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity,

225

Class<T> responseType, Map<String, ?> uriVariables);

226

<T> ResponseEntity<T> exchange(URI url, HttpMethod method, HttpEntity<?> requestEntity,

227

Class<T> responseType);

228

<T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, Class<T> responseType);

229

<T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, ParameterizedTypeReference<T> responseType);

230

231

// Async execute methods

232

<T> ListenableFuture<ResponseEntity<T>> execute(String url, HttpMethod method,

233

RequestCallback requestCallback,

234

ResponseExtractor<ResponseEntity<T>> responseExtractor,

235

Object... uriVariables);

236

}

237

238

/**

239

* RestOperations interface defining the template contract

240

*/

241

interface RestOperations {

242

// All the same methods as RestTemplate class

243

// This interface is implemented by RestTemplate

244

}

245

```

246

247

**Usage Examples:**

248

249

```java

250

RestTemplate restTemplate = new RestTemplate();

251

252

// Simple GET operations

253

String result = restTemplate.getForObject("https://api.example.com/users/{id}", String.class, 123);

254

ResponseEntity<User> userResponse = restTemplate.getForEntity("https://api.example.com/users/{id}", User.class, 123);

255

256

// POST operations

257

User newUser = new User("John", "john@example.com");

258

User createdUser = restTemplate.postForObject("https://api.example.com/users", newUser, User.class);

259

URI location = restTemplate.postForLocation("https://api.example.com/users", newUser);

260

261

// Exchange for full control

262

HttpHeaders headers = new HttpHeaders();

263

headers.setBearerAuth("token");

264

HttpEntity<User> requestEntity = new HttpEntity<>(newUser, headers);

265

266

ResponseEntity<User> response = restTemplate.exchange(

267

"https://api.example.com/users",

268

HttpMethod.POST,

269

requestEntity,

270

User.class

271

);

272

273

// Using RequestEntity

274

RequestEntity<User> request = RequestEntity.post("https://api.example.com/users")

275

.contentType(MediaType.APPLICATION_JSON)

276

.body(newUser);

277

278

ResponseEntity<User> response = restTemplate.exchange(request, User.class);

279

```

280

281

### HTTP Client Infrastructure

282

283

Low-level HTTP client infrastructure for creating and configuring HTTP requests and responses.

284

285

```java { .api }

286

/**

287

* Factory for creating ClientHttpRequest objects

288

*/

289

interface ClientHttpRequestFactory {

290

/** Create a new request for the given URI and HTTP method */

291

ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException;

292

}

293

294

/**

295

* Client-side HTTP request

296

*/

297

interface ClientHttpRequest extends HttpRequest, HttpOutputMessage {

298

/** Execute this request and return the response */

299

ClientHttpResponse execute() throws IOException;

300

}

301

302

/**

303

* Client-side HTTP response

304

*/

305

interface ClientHttpResponse extends HttpInputMessage, Closeable {

306

/** Get the HTTP status code */

307

HttpStatusCode getStatusCode() throws IOException;

308

/** Get the status text */

309

String getStatusText() throws IOException;

310

/** Close this response */

311

void close();

312

}

313

314

/**

315

* Execution context for client HTTP requests

316

*/

317

interface ClientHttpRequestExecution {

318

/** Execute the request with the given body */

319

ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException;

320

}

321

322

/**

323

* Interceptor for client-side HTTP requests

324

*/

325

interface ClientHttpRequestInterceptor {

326

/** Intercept the request before execution */

327

ClientHttpResponse intercept(HttpRequest request, byte[] body,

328

ClientHttpRequestExecution execution) throws IOException;

329

}

330

331

/**

332

* Initializer for client HTTP requests

333

*/

334

interface ClientHttpRequestInitializer {

335

/** Initialize the request before execution */

336

void initialize(ClientHttpRequest request);

337

}

338

```

339

340

### HTTP Client Factory Implementations

341

342

Concrete implementations of ClientHttpRequestFactory for different HTTP client libraries.

343

344

```java { .api }

345

/**

346

* Simple factory based on standard JDK HTTP facilities

347

*/

348

class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory {

349

SimpleClientHttpRequestFactory();

350

351

/** Set the proxy to use for connections */

352

void setProxy(Proxy proxy);

353

/** Set whether to buffer request body in memory */

354

void setBufferRequestBody(boolean bufferRequestBody);

355

/** Set the chunk size for streaming */

356

void setChunkSize(int chunkSize);

357

/** Set the connection timeout */

358

void setConnectTimeout(int connectTimeout);

359

/** Set the read timeout */

360

void setReadTimeout(int readTimeout);

361

362

ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException;

363

}

364

365

/**

366

* Factory based on Apache HttpComponents HttpClient

367

*/

368

class HttpComponentsClientHttpRequestFactory implements ClientHttpRequestFactory, DisposableBean {

369

HttpComponentsClientHttpRequestFactory();

370

HttpComponentsClientHttpRequestFactory(HttpClient httpClient);

371

372

/** Set the HttpClient instance to use */

373

void setHttpClient(HttpClient httpClient);

374

/** Set connection timeout */

375

void setConnectTimeout(int connectTimeout);

376

/** Set connection request timeout */

377

void setConnectionRequestTimeout(int connectionRequestTimeout);

378

/** Set socket read timeout */

379

void setReadTimeout(int readTimeout);

380

/** Set buffer request body */

381

void setBufferRequestBody(boolean bufferRequestBody);

382

383

ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException;

384

void destroy() throws Exception;

385

}

386

387

/**

388

* Factory based on OkHttp 3.x

389

*/

390

class OkHttp3ClientHttpRequestFactory implements ClientHttpRequestFactory, DisposableBean {

391

OkHttp3ClientHttpRequestFactory();

392

OkHttp3ClientHttpRequestFactory(OkHttpClient client);

393

394

/** Set the OkHttpClient instance to use */

395

void setClient(OkHttpClient client);

396

/** Set connection timeout */

397

void setConnectTimeout(int connectTimeout);

398

/** Set read timeout */

399

void setReadTimeout(int readTimeout);

400

/** Set write timeout */

401

void setWriteTimeout(int writeTimeout);

402

403

ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException;

404

void destroy() throws Exception;

405

}

406

407

/**

408

* Factory based on JDK 11+ HTTP Client

409

*/

410

class JdkClientHttpRequestFactory implements ClientHttpRequestFactory {

411

JdkClientHttpRequestFactory();

412

JdkClientHttpRequestFactory(HttpClient httpClient);

413

JdkClientHttpRequestFactory(HttpClient httpClient, Executor executor);

414

415

/** Set the HttpClient instance to use */

416

void setHttpClient(HttpClient httpClient);

417

/** Set executor for async operations */

418

void setExecutor(Executor executor);

419

/** Set read timeout */

420

void setReadTimeout(Duration readTimeout);

421

422

ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException;

423

}

424

425

/**

426

* Factory wrapper that buffers all outgoing and incoming streams

427

*/

428

class BufferingClientHttpRequestFactory extends AbstractClientHttpRequestFactoryWrapper {

429

BufferingClientHttpRequestFactory(ClientHttpRequestFactory requestFactory);

430

431

ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) throws IOException;

432

}

433

434

/**

435

* Factory wrapper with support for request interceptors

436

*/

437

class InterceptingClientHttpRequestFactory extends AbstractClientHttpRequestFactoryWrapper {

438

InterceptingClientHttpRequestFactory(ClientHttpRequestFactory requestFactory,

439

List<ClientHttpRequestInterceptor> interceptors);

440

441

ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) throws IOException;

442

}

443

```

444

445

**Usage Examples:**

446

447

```java

448

// Configure different HTTP client factories

449

SimpleClientHttpRequestFactory simpleFactory = new SimpleClientHttpRequestFactory();

450

simpleFactory.setConnectTimeout(5000);

451

simpleFactory.setReadTimeout(10000);

452

453

HttpComponentsClientHttpRequestFactory httpComponentsFactory = new HttpComponentsClientHttpRequestFactory();

454

httpComponentsFactory.setConnectTimeout(5000);

455

httpComponentsFactory.setReadTimeout(10000);

456

457

// Use with RestTemplate

458

RestTemplate restTemplate = new RestTemplate(simpleFactory);

459

460

// Configure with interceptors

461

List<ClientHttpRequestInterceptor> interceptors = Arrays.asList(

462

new BasicAuthenticationInterceptor("username", "password"),

463

new LoggingClientHttpRequestInterceptor()

464

);

465

466

restTemplate.setInterceptors(interceptors);

467

```

468

469

### Request Interceptors and Authentication

470

471

Built-in interceptors for common cross-cutting concerns like authentication and logging.

472

473

```java { .api }

474

/**

475

* Interceptor to apply Basic Authentication headers

476

*/

477

class BasicAuthenticationInterceptor implements ClientHttpRequestInterceptor {

478

BasicAuthenticationInterceptor(String username, String password);

479

BasicAuthenticationInterceptor(String username, String password, Charset charset);

480

481

ClientHttpResponse intercept(HttpRequest request, byte[] body,

482

ClientHttpRequestExecution execution) throws IOException;

483

}

484

485

/**

486

* Interceptor to apply Bearer token authentication

487

*/

488

class BearerTokenAuthenticationInterceptor implements ClientHttpRequestInterceptor {

489

BearerTokenAuthenticationInterceptor(String token);

490

491

ClientHttpResponse intercept(HttpRequest request, byte[] body,

492

ClientHttpRequestExecution execution) throws IOException;

493

}

494

```

495

496

**Usage Examples:**

497

498

```java

499

// Basic authentication interceptor

500

BasicAuthenticationInterceptor basicAuth = new BasicAuthenticationInterceptor("user", "pass");

501

502

// Bearer token interceptor

503

BearerTokenAuthenticationInterceptor bearerAuth = new BearerTokenAuthenticationInterceptor("jwt-token");

504

505

// Custom interceptor

506

ClientHttpRequestInterceptor customInterceptor = (request, body, execution) -> {

507

request.getHeaders().add("X-Custom-Header", "custom-value");

508

ClientHttpResponse response = execution.execute(request, body);

509

// Log response or modify headers

510

return response;

511

};

512

513

// Apply interceptors to RestTemplate

514

RestTemplate restTemplate = new RestTemplate();

515

restTemplate.setInterceptors(Arrays.asList(basicAuth, customInterceptor));

516

517

// Apply interceptors to RestClient

518

RestClient restClient = RestClient.builder()

519

.requestInterceptor(bearerAuth)

520

.requestInterceptor(customInterceptor)

521

.build();

522

```

523

524

### Error Handling

525

526

Configure custom error handling for HTTP client responses.

527

528

```java { .api }

529

/**

530

* Strategy interface used by RestTemplate to determine whether a response has an error

531

*/

532

interface ResponseErrorHandler {

533

/** Determine if the given response has an error */

534

boolean hasError(ClientHttpResponse response) throws IOException;

535

/** Handle the error in the given response */

536

void handleError(ClientHttpResponse response) throws IOException;

537

/** Handle the error for the given request and response */

538

default void handleError(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {

539

handleError(response);

540

}

541

}

542

543

/**

544

* Default implementation of ResponseErrorHandler

545

*/

546

class DefaultResponseErrorHandler implements ResponseErrorHandler {

547

DefaultResponseErrorHandler();

548

549

/** Check if response has client (4xx) or server (5xx) error */

550

boolean hasError(ClientHttpResponse response) throws IOException;

551

/** Throw appropriate exception based on status code */

552

void handleError(ClientHttpResponse response) throws IOException;

553

void handleError(URI url, HttpMethod method, ClientHttpResponse response) throws IOException;

554

555

// Template methods for customization

556

protected boolean hasError(HttpStatusCode statusCode);

557

protected void handleError(ClientHttpResponse response, HttpStatusCode statusCode) throws IOException;

558

}

559

```

560

561

**Usage Examples:**

562

563

```java

564

// Custom error handler

565

ResponseErrorHandler customErrorHandler = new ResponseErrorHandler() {

566

@Override

567

public boolean hasError(ClientHttpResponse response) throws IOException {

568

return response.getStatusCode().is4xxClientError() ||

569

response.getStatusCode().is5xxServerError();

570

}

571

572

@Override

573

public void handleError(ClientHttpResponse response) throws IOException {

574

HttpStatusCode statusCode = response.getStatusCode();

575

if (statusCode.is4xxClientError()) {

576

throw new ClientErrorException("Client error: " + statusCode);

577

}

578

if (statusCode.is5xxServerError()) {

579

throw new ServerErrorException("Server error: " + statusCode);

580

}

581

}

582

};

583

584

// Apply to RestTemplate

585

RestTemplate restTemplate = new RestTemplate();

586

restTemplate.setErrorHandler(customErrorHandler);

587

588

// Apply to RestClient

589

RestClient restClient = RestClient.builder()

590

.defaultStatusHandler(HttpStatus::is4xxClientError,

591

(request, response) -> {

592

throw new ClientErrorException(response.getStatusCode());

593

})

594

.build();

595

```