or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdconnection-pooling.mdcontent-management.mdhttp-operations.mdindex.mdproxy-configuration.mdrequest-configuration.mdresponse-processing.md

response-processing.mddocs/

0

# Response Processing

1

2

The response processing capability provides comprehensive response handling including status codes, headers, content processing, and streaming capabilities with multiple listener patterns for both synchronous and asynchronous response handling.

3

4

## Response Interface

5

6

The core interface for accessing HTTP response information.

7

8

```java { .api }

9

public interface Response {

10

// Request association

11

Request getRequest();

12

13

// Status information

14

HttpVersion getVersion();

15

int getStatus();

16

String getReason();

17

18

// Headers and trailers

19

HttpFields getHeaders();

20

HttpFields getTrailers();

21

22

// Listener interfaces for event-driven processing

23

interface Listener extends EventListener {

24

default void onBegin(Response response) {}

25

default void onHeader(Response response, HttpField field) {}

26

default void onHeaders(Response response) {}

27

default void onContent(Response response, ByteBuffer content) {}

28

default void onSuccess(Response response) {}

29

default void onFailure(Response response, Throwable failure) {}

30

default void onComplete(Result result) {}

31

}

32

33

interface CompleteListener extends Listener {

34

void onComplete(Result result);

35

}

36

37

interface BeginListener extends EventListener {

38

void onBegin(Response response);

39

}

40

41

interface HeaderListener extends EventListener {

42

void onHeader(Response response, HttpField field);

43

}

44

45

interface HeadersListener extends EventListener {

46

void onHeaders(Response response);

47

}

48

49

interface ContentListener extends EventListener {

50

void onContent(Response response, ByteBuffer content);

51

}

52

53

interface DemandedContentListener extends EventListener {

54

void onContent(Response response, LongConsumer demand, ByteBuffer content);

55

}

56

57

interface SuccessListener extends EventListener {

58

void onSuccess(Response response);

59

}

60

61

interface FailureListener extends EventListener {

62

void onFailure(Response response, Throwable failure);

63

}

64

}

65

```

66

67

## ContentResponse Interface

68

69

Extended response interface that provides access to buffered response content.

70

71

```java { .api }

72

public interface ContentResponse extends Response {

73

// Content access

74

String getMediaType();

75

String getEncoding();

76

byte[] getContent();

77

String getContentAsString();

78

String getContentAsString(String encoding);

79

80

// Factory method

81

static ContentResponse from(Response response, byte[] content, String mediaType, String encoding);

82

}

83

```

84

85

## Basic Response Access

86

87

### Synchronous Response Handling

88

89

```java

90

ContentResponse response = client.GET("https://api.example.com/users");

91

92

// Status information

93

int status = response.getStatus();

94

String reason = response.getReason();

95

HttpVersion version = response.getVersion();

96

97

System.out.println("Status: " + status + " " + reason);

98

System.out.println("HTTP Version: " + version);

99

100

// Content access

101

byte[] contentBytes = response.getContent();

102

String contentString = response.getContentAsString();

103

String mediaType = response.getMediaType();

104

String encoding = response.getEncoding();

105

106

System.out.println("Content Type: " + mediaType);

107

System.out.println("Content Length: " + contentBytes.length);

108

System.out.println("Content: " + contentString);

109

```

110

111

### Response Headers

112

113

```java

114

ContentResponse response = client.GET("https://api.example.com/data");

115

116

HttpFields headers = response.getHeaders();

117

118

// Access specific headers

119

String contentType = headers.get("Content-Type");

120

String serverHeader = headers.get("Server");

121

String cacheControl = headers.get("Cache-Control");

122

123

// Iterate through all headers

124

for (HttpField field : headers) {

125

System.out.println(field.getName() + ": " + field.getValue());

126

}

127

128

// Check for header existence

129

if (headers.contains("X-Rate-Limit-Remaining")) {

130

String rateLimit = headers.get("X-Rate-Limit-Remaining");

131

System.out.println("Remaining requests: " + rateLimit);

132

}

133

```

134

135

## Asynchronous Response Processing

136

137

### Using Response Listeners

138

139

Process responses as they arrive without blocking:

140

141

```java

142

client.newRequest("https://api.example.com/stream")

143

.send(new Response.Listener() {

144

@Override

145

public void onBegin(Response response) {

146

System.out.println("Response begun: " + response.getStatus());

147

}

148

149

@Override

150

public void onHeaders(Response response) {

151

HttpFields headers = response.getHeaders();

152

String contentType = headers.get("Content-Type");

153

System.out.println("Content-Type: " + contentType);

154

}

155

156

@Override

157

public void onContent(Response response, ByteBuffer content) {

158

// Process content as it arrives

159

byte[] bytes = new byte[content.remaining()];

160

content.get(bytes);

161

System.out.println("Received chunk: " + bytes.length + " bytes");

162

}

163

164

@Override

165

public void onSuccess(Response response) {

166

System.out.println("Response completed successfully");

167

}

168

169

@Override

170

public void onFailure(Response response, Throwable failure) {

171

System.err.println("Response failed: " + failure.getMessage());

172

}

173

});

174

```

175

176

### Using Complete Listener

177

178

Simplified listener for complete response handling:

179

180

```java

181

client.newRequest("https://api.example.com/data")

182

.send(result -> {

183

if (result.isSucceeded()) {

184

Response response = result.getResponse();

185

System.out.println("Success: " + response.getStatus());

186

187

// Access request that generated this response

188

Request request = result.getRequest();

189

System.out.println("Original URL: " + request.getURI());

190

} else {

191

Throwable failure = result.getFailure();

192

System.err.println("Request failed: " + failure.getMessage());

193

}

194

});

195

```

196

197

## Specialized Response Listeners

198

199

### BufferingResponseListener

200

201

Automatically buffers response content in memory:

202

203

```java { .api }

204

public class BufferingResponseListener extends Response.Listener.Adapter {

205

public BufferingResponseListener();

206

public BufferingResponseListener(int maxLength);

207

208

public byte[] getContent();

209

public String getContentAsString();

210

public String getContentAsString(String encoding);

211

public String getMediaType();

212

public String getEncoding();

213

}

214

```

215

216

```java

217

BufferingResponseListener listener = new BufferingResponseListener();

218

219

client.newRequest("https://api.example.com/data")

220

.send(listener);

221

222

// Wait for completion and access buffered content

223

Response response = listener.get(5, TimeUnit.SECONDS);

224

byte[] content = listener.getContent();

225

String contentString = listener.getContentAsString();

226

```

227

228

### InputStreamResponseListener

229

230

Provides InputStream access to response content:

231

232

```java { .api }

233

public class InputStreamResponseListener extends Response.Listener.Adapter {

234

public InputStreamResponseListener();

235

236

public InputStream getInputStream();

237

public Response get(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException, ExecutionException;

238

}

239

```

240

241

```java

242

InputStreamResponseListener listener = new InputStreamResponseListener();

243

244

client.newRequest("https://api.example.com/large-file")

245

.send(listener);

246

247

// Get the InputStream to read content

248

try (InputStream inputStream = listener.getInputStream()) {

249

// Process stream as data arrives

250

byte[] buffer = new byte[8192];

251

int bytesRead;

252

while ((bytesRead = inputStream.read(buffer)) != -1) {

253

// Process buffer content

254

processData(buffer, 0, bytesRead);

255

}

256

}

257

```

258

259

### PathResponseListener

260

261

Saves response content directly to a file:

262

263

```java { .api }

264

public class PathResponseListener extends Response.Listener.Adapter {

265

public PathResponseListener(Path file);

266

public PathResponseListener(Path file, boolean overwrite);

267

268

public Path getPath();

269

}

270

```

271

272

```java

273

Path downloadPath = Paths.get("/tmp/downloaded-file.zip");

274

PathResponseListener listener = new PathResponseListener(downloadPath, true);

275

276

client.newRequest("https://api.example.com/download/file.zip")

277

.send(listener);

278

279

// Wait for download completion

280

Response response = listener.get(30, TimeUnit.SECONDS);

281

if (response.getStatus() == 200) {

282

System.out.println("File downloaded to: " + downloadPath);

283

}

284

```

285

286

### FutureResponseListener

287

288

CompletableFuture-based response handling:

289

290

```java { .api }

291

public class FutureResponseListener extends BufferingResponseListener implements Future<ContentResponse> {

292

public FutureResponseListener(Request request);

293

public FutureResponseListener(Request request, int maxLength);

294

}

295

```

296

297

```java

298

Request request = client.newRequest("https://api.example.com/data");

299

FutureResponseListener listener = new FutureResponseListener(request);

300

301

request.send(listener);

302

303

// Use as Future

304

ContentResponse response = listener.get(10, TimeUnit.SECONDS);

305

String content = response.getContentAsString();

306

```

307

308

## Result Interface

309

310

The Result interface provides access to the complete request/response cycle:

311

312

```java { .api }

313

public interface Result {

314

Request getRequest();

315

Response getResponse();

316

Throwable getRequestFailure();

317

Throwable getResponseFailure();

318

boolean isSucceeded();

319

boolean isFailed();

320

}

321

```

322

323

### Result Processing

324

325

```java

326

client.newRequest("https://api.example.com/data")

327

.send(result -> {

328

Request request = result.getRequest();

329

System.out.println("Request URL: " + request.getURI());

330

331

if (result.isSucceeded()) {

332

Response response = result.getResponse();

333

System.out.println("Response status: " + response.getStatus());

334

} else {

335

// Check for request vs response failures

336

Throwable requestFailure = result.getRequestFailure();

337

Throwable responseFailure = result.getResponseFailure();

338

339

if (requestFailure != null) {

340

System.err.println("Request failed: " + requestFailure.getMessage());

341

}

342

if (responseFailure != null) {

343

System.err.println("Response failed: " + responseFailure.getMessage());

344

}

345

}

346

});

347

```

348

349

## Status Code Handling

350

351

### Common Status Code Patterns

352

353

```java

354

ContentResponse response = client.GET("https://api.example.com/resource");

355

356

switch (response.getStatus()) {

357

case 200:

358

// OK - process successful response

359

String content = response.getContentAsString();

360

break;

361

362

case 201:

363

// Created - resource created successfully

364

String location = response.getHeaders().get("Location");

365

break;

366

367

case 204:

368

// No Content - successful operation with no response body

369

break;

370

371

case 301:

372

case 302:

373

// Redirects - typically handled automatically by client

374

String location = response.getHeaders().get("Location");

375

break;

376

377

case 400:

378

// Bad Request - client error

379

String errorDetails = response.getContentAsString();

380

throw new IllegalArgumentException("Bad request: " + errorDetails);

381

382

case 401:

383

// Unauthorized - authentication required

384

throw new SecurityException("Authentication required");

385

386

case 403:

387

// Forbidden - access denied

388

throw new SecurityException("Access forbidden");

389

390

case 404:

391

// Not Found - resource doesn't exist

392

throw new IllegalArgumentException("Resource not found");

393

394

case 429:

395

// Too Many Requests - rate limiting

396

String retryAfter = response.getHeaders().get("Retry-After");

397

throw new RuntimeException("Rate limited. Retry after: " + retryAfter);

398

399

case 500:

400

// Internal Server Error

401

throw new RuntimeException("Server error: " + response.getReason());

402

403

default:

404

if (response.getStatus() >= 400) {

405

throw new RuntimeException("HTTP error: " + response.getStatus() + " " + response.getReason());

406

}

407

}

408

```

409

410

### Status Code Categories

411

412

```java

413

ContentResponse response = client.GET("https://api.example.com/data");

414

int status = response.getStatus();

415

416

if (status >= 200 && status < 300) {

417

// Success responses

418

handleSuccess(response);

419

} else if (status >= 300 && status < 400) {

420

// Redirection responses (usually handled automatically)

421

handleRedirect(response);

422

} else if (status >= 400 && status < 500) {

423

// Client error responses

424

handleClientError(response);

425

} else if (status >= 500) {

426

// Server error responses

427

handleServerError(response);

428

}

429

```

430

431

## Advanced Response Processing

432

433

### Content Type Processing

434

435

```java

436

ContentResponse response = client.GET("https://api.example.com/data");

437

438

String contentType = response.getMediaType();

439

String encoding = response.getEncoding();

440

441

if ("application/json".equals(contentType)) {

442

String json = response.getContentAsString();

443

// Parse JSON content

444

} else if ("application/xml".equals(contentType)) {

445

String xml = response.getContentAsString();

446

// Parse XML content

447

} else if (contentType != null && contentType.startsWith("text/")) {

448

String text = response.getContentAsString(encoding);

449

// Process text content

450

} else {

451

byte[] binaryData = response.getContent();

452

// Process binary content

453

}

454

```

455

456

### Large Response Streaming

457

458

```java

459

client.newRequest("https://api.example.com/large-dataset")

460

.send(new Response.Listener() {

461

private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();

462

463

@Override

464

public void onContent(Response response, ByteBuffer content) {

465

// Stream content to avoid memory issues

466

byte[] bytes = new byte[content.remaining()];

467

content.get(bytes);

468

469

try {

470

buffer.write(bytes);

471

472

// Process buffer when it reaches a certain size

473

if (buffer.size() > 64 * 1024) { // 64KB chunks

474

processChunk(buffer.toByteArray());

475

buffer.reset();

476

}

477

} catch (IOException e) {

478

throw new RuntimeException("Failed to process content", e);

479

}

480

}

481

482

@Override

483

public void onSuccess(Response response) {

484

// Process any remaining content

485

if (buffer.size() > 0) {

486

processChunk(buffer.toByteArray());

487

}

488

}

489

});

490

```

491

492

### Response Validation

493

494

```java

495

public class ValidatingResponseListener extends Response.Listener.Adapter {

496

@Override

497

public void onHeaders(Response response) {

498

// Validate response headers

499

HttpFields headers = response.getHeaders();

500

501

String contentType = headers.get("Content-Type");

502

if (contentType == null || !contentType.startsWith("application/json")) {

503

throw new IllegalStateException("Expected JSON response, got: " + contentType);

504

}

505

506

String contentLength = headers.get("Content-Length");

507

if (contentLength != null) {

508

long length = Long.parseLong(contentLength);

509

if (length > MAX_RESPONSE_SIZE) {

510

throw new IllegalStateException("Response too large: " + length);

511

}

512

}

513

}

514

515

@Override

516

public void onSuccess(Response response) {

517

if (response.getStatus() != 200) {

518

throw new IllegalStateException("Expected 200 OK, got: " + response.getStatus());

519

}

520

}

521

}

522

```