or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdhttp-routing.mdhttp-services.mdhttp1-protocol.mdindex.mdrequest-response.mdserver-management.mdspi.md

request-response.mddocs/

0

# Request and Response Handling

1

2

Complete HTTP request and response interfaces with entity handling, headers, parameters, and content negotiation for comprehensive HTTP communication.

3

4

## Capabilities

5

6

### Handler Interface

7

8

The core interface for processing HTTP requests and generating responses.

9

10

```java { .api }

11

/**

12

* Interface for handling HTTP requests.

13

*/

14

interface Handler {

15

/**

16

* Handle HTTP request and generate response.

17

* @param req server request

18

* @param res server response

19

*/

20

void handle(ServerRequest req, ServerResponse res);

21

22

/**

23

* Create handler from consumer function.

24

* @param handler consumer that processes the request

25

* @return new handler instance

26

*/

27

static Handler create(Consumer<ServerRequest> handler);

28

29

/**

30

* Create handler from function that returns response data.

31

* @param handler function that processes request and returns response data

32

* @return new handler instance

33

*/

34

static Handler create(Function<ServerRequest, ?> handler);

35

36

/**

37

* Create handler from supplier that returns response data.

38

* @param handler supplier that returns response data

39

* @return new handler instance

40

*/

41

static Handler create(Supplier<?> handler);

42

}

43

```

44

45

**Usage Examples:**

46

47

```java

48

import io.helidon.webserver.http.Handler;

49

50

// Lambda handler

51

Handler lambdaHandler = (req, res) -> {

52

res.send("Hello from lambda");

53

};

54

55

// Consumer-based handler

56

Handler consumerHandler = Handler.create(req -> {

57

System.out.println("Processing request: " + req.method());

58

});

59

60

// Function-based handler

61

Handler functionHandler = Handler.create(req -> {

62

return "Response for " + req.path().path();

63

});

64

65

// Supplier-based handler

66

Handler supplierHandler = Handler.create(() -> {

67

return "Fixed response";

68

});

69

```

70

71

### ServerRequest Interface

72

73

Interface for accessing HTTP request data, headers, parameters, and body content.

74

75

```java { .api }

76

/**

77

* HTTP server request interface.

78

*/

79

interface ServerRequest extends HttpRequest {

80

/**

81

* Get request path information.

82

* @return path information with parameters and matchers

83

*/

84

ServerRequestPath path();

85

86

/**

87

* Get request query parameters.

88

* @return query parameters

89

*/

90

Parameters query();

91

92

/**

93

* Get request headers.

94

* @return request headers

95

*/

96

ServerRequestHeaders headers();

97

98

/**

99

* Get request entity (body).

100

* @return request entity

101

*/

102

ServerRequestEntity entity();

103

104

/**

105

* Get HTTP method.

106

* @return HTTP method

107

*/

108

Method method();

109

110

/**

111

* Get request URI.

112

* @return request URI

113

*/

114

UriInfo requestedUri();

115

116

/**

117

* Get local address of the connection.

118

* @return local address

119

*/

120

String localAddress();

121

122

/**

123

* Get local port of the connection.

124

* @return local port

125

*/

126

int localPort();

127

128

/**

129

* Get remote address of the connection.

130

* @return remote address

131

*/

132

String remoteAddress();

133

134

/**

135

* Get remote port of the connection.

136

* @return remote port

137

*/

138

int remotePort();

139

140

/**

141

* Check if connection is secure (TLS).

142

* @return true if secure connection

143

*/

144

boolean isSecure();

145

146

/**

147

* Get server request context.

148

* @return request context

149

*/

150

Context context();

151

}

152

```

153

154

**Usage Examples:**

155

156

```java

157

Handler requestInfoHandler = (req, res) -> {

158

// Access request information

159

String method = req.method().text();

160

String path = req.path().path();

161

String remoteAddr = req.remoteAddress();

162

boolean secure = req.isSecure();

163

164

// Access path parameters

165

Map<String, String> pathParams = req.path().pathParameters().toMap();

166

String userId = pathParams.get("id");

167

168

// Access query parameters

169

Optional<String> filter = req.query().first("filter");

170

List<String> tags = req.query().all("tag");

171

172

// Access headers

173

Optional<String> contentType = req.headers().contentType()

174

.map(MediaType::text);

175

Optional<String> userAgent = req.headers().first("User-Agent");

176

177

// Build response

178

String info = String.format(

179

"Method: %s, Path: %s, Remote: %s, Secure: %s",

180

method, path, remoteAddr, secure

181

);

182

183

res.send(info);

184

};

185

```

186

187

### ServerResponse Interface

188

189

Interface for generating HTTP responses with status codes, headers, and body content.

190

191

```java { .api }

192

/**

193

* HTTP server response interface.

194

*/

195

interface ServerResponse {

196

/**

197

* Set response status code.

198

* @param status HTTP status

199

* @return this response for chaining

200

*/

201

ServerResponse status(Status status);

202

203

/**

204

* Set response status code.

205

* @param statusCode HTTP status code

206

* @return this response for chaining

207

*/

208

ServerResponse status(int statusCode);

209

210

/**

211

* Add response header.

212

* @param name header name

213

* @param value header value

214

* @return this response for chaining

215

*/

216

ServerResponse header(String name, String value);

217

218

/**

219

* Add response header with multiple values.

220

* @param name header name

221

* @param values header values

222

* @return this response for chaining

223

*/

224

ServerResponse header(String name, String... values);

225

226

/**

227

* Set response headers.

228

* @param headers headers to set

229

* @return this response for chaining

230

*/

231

ServerResponse headers(WritableHeaders<?> headers);

232

233

/**

234

* Set content type.

235

* @param contentType media type

236

* @return this response for chaining

237

*/

238

ServerResponse contentType(MediaType contentType);

239

240

/**

241

* Send response with string content.

242

* @param entity response content

243

*/

244

void send(String entity);

245

246

/**

247

* Send response with byte array content.

248

* @param entity response content

249

*/

250

void send(byte[] entity);

251

252

/**

253

* Send response with input stream content.

254

* @param entity response content

255

*/

256

void send(InputStream entity);

257

258

/**

259

* Send response with object content (uses media support for serialization).

260

* @param entity response object

261

*/

262

void send(Object entity);

263

264

/**

265

* Send empty response.

266

*/

267

void send();

268

269

/**

270

* Re-route request to different path.

271

* @param path new path

272

*/

273

void reroute(String path);

274

275

/**

276

* Re-route request to different path with query parameters.

277

* @param path new path

278

* @param queryParams query parameters

279

*/

280

void reroute(String path, UriQuery queryParams);

281

282

/**

283

* Get response headers for modification.

284

* @return response headers

285

*/

286

ServerResponseHeaders headers();

287

288

/**

289

* Check if response headers have been sent.

290

* @return true if headers sent

291

*/

292

boolean headersSent();

293

294

/**

295

* Get server response context.

296

* @return response context

297

*/

298

Context context();

299

}

300

```

301

302

**Usage Examples:**

303

304

```java

305

import io.helidon.http.Status;

306

import io.helidon.http.MediaType;

307

308

// Basic response handling

309

Handler basicHandler = (req, res) -> {

310

res.status(Status.OK_200)

311

.contentType(MediaType.TEXT_PLAIN)

312

.send("Hello World");

313

};

314

315

// JSON response

316

Handler jsonHandler = (req, res) -> {

317

Map<String, Object> data = Map.of(

318

"message", "Hello",

319

"timestamp", System.currentTimeMillis()

320

);

321

322

res.status(Status.OK_200)

323

.contentType(MediaType.APPLICATION_JSON)

324

.send(data); // Automatically serialized to JSON

325

};

326

327

// Custom headers

328

Handler customHeadersHandler = (req, res) -> {

329

res.status(Status.OK_200)

330

.header("X-Custom-Header", "CustomValue")

331

.header("Cache-Control", "no-cache", "no-store")

332

.contentType(MediaType.TEXT_HTML)

333

.send("<h1>Custom Response</h1>");

334

};

335

336

// File download

337

Handler downloadHandler = (req, res) -> {

338

try {

339

Path filePath = Paths.get("data.pdf");

340

byte[] fileContent = Files.readAllBytes(filePath);

341

342

res.status(Status.OK_200)

343

.contentType(MediaType.APPLICATION_OCTET_STREAM)

344

.header("Content-Disposition", "attachment; filename=data.pdf")

345

.send(fileContent);

346

} catch (IOException e) {

347

res.status(Status.INTERNAL_SERVER_ERROR_500)

348

.send("File not found");

349

}

350

};

351

352

// Streaming response

353

Handler streamHandler = (req, res) -> {

354

try {

355

InputStream stream = new FileInputStream("large-file.txt");

356

res.status(Status.OK_200)

357

.contentType(MediaType.TEXT_PLAIN)

358

.send(stream); // Automatically streams content

359

} catch (FileNotFoundException e) {

360

res.status(Status.NOT_FOUND_404).send("File not found");

361

}

362

};

363

```

364

365

### ServerRequestEntity Interface

366

367

Interface for accessing request body content with various content types.

368

369

```java { .api }

370

/**

371

* Entity part of server request for accessing request body.

372

*/

373

interface ServerRequestEntity {

374

/**

375

* Get entity as string.

376

* @return entity content as string

377

*/

378

String as(Class<String> type);

379

380

/**

381

* Get entity as byte array.

382

* @return entity content as byte array

383

*/

384

byte[] as(Class<byte[]> type);

385

386

/**

387

* Get entity as input stream.

388

* @return entity content as input stream

389

*/

390

InputStream as(Class<InputStream> type);

391

392

/**

393

* Get entity as specific type using media support.

394

* @param type target type

395

* @param <T> type parameter

396

* @return entity converted to target type

397

*/

398

<T> T as(Class<T> type);

399

400

/**

401

* Get entity as generic type using media support.

402

* @param type generic type token

403

* @param <T> type parameter

404

* @return entity converted to target type

405

*/

406

<T> T as(GenericType<T> type);

407

408

/**

409

* Check if entity is available.

410

* @return true if entity is present

411

*/

412

boolean hasEntity();

413

414

/**

415

* Get entity content type.

416

* @return media type of entity

417

*/

418

Optional<MediaType> contentType();

419

420

/**

421

* Get entity content length.

422

* @return content length if known

423

*/

424

OptionalLong contentLength();

425

}

426

```

427

428

**Usage Examples:**

429

430

```java

431

// Handle different content types

432

Handler entityHandler = (req, res) -> {

433

ServerRequestEntity entity = req.entity();

434

435

if (!entity.hasEntity()) {

436

res.status(Status.BAD_REQUEST_400).send("Request body required");

437

return;

438

}

439

440

Optional<MediaType> contentType = entity.contentType();

441

442

if (contentType.isPresent()) {

443

if (MediaType.APPLICATION_JSON.test(contentType.get())) {

444

// Handle JSON

445

Map<String, Object> jsonData = entity.as(Map.class);

446

res.send("Received JSON: " + jsonData);

447

448

} else if (MediaType.TEXT_PLAIN.test(contentType.get())) {

449

// Handle text

450

String textData = entity.as(String.class);

451

res.send("Received text: " + textData);

452

453

} else if (MediaType.APPLICATION_OCTET_STREAM.test(contentType.get())) {

454

// Handle binary data

455

byte[] binaryData = entity.as(byte[].class);

456

res.send("Received " + binaryData.length + " bytes");

457

458

} else {

459

res.status(Status.UNSUPPORTED_MEDIA_TYPE_415)

460

.send("Unsupported content type");

461

}

462

} else {

463

// Default handling

464

String content = entity.as(String.class);

465

res.send("Received: " + content);

466

}

467

};

468

469

// Custom object deserialization

470

Handler userHandler = (req, res) -> {

471

try {

472

User user = req.entity().as(User.class); // Auto-deserialize JSON to User

473

// Process user object

474

res.status(Status.CREATED_201).send("User created: " + user.getName());

475

} catch (Exception e) {

476

res.status(Status.BAD_REQUEST_400).send("Invalid user data");

477

}

478

};

479

```

480

481

### ServerRequestPath Interface

482

483

Interface for accessing path information, parameters, and matching details.

484

485

```java { .api }

486

/**

487

* Server request path information.

488

*/

489

interface ServerRequestPath {

490

/**

491

* Get absolute path of the request.

492

* @return absolute path

493

*/

494

String path();

495

496

/**

497

* Get path parameters extracted from path pattern.

498

* @return path parameters

499

*/

500

Parameters pathParameters();

501

502

/**

503

* Get matched path pattern.

504

* @return path pattern that matched this request

505

*/

506

Optional<String> pathPattern();

507

508

/**

509

* Get path matcher used for matching.

510

* @return path matcher

511

*/

512

Optional<PathMatcher> pathMatcher();

513

514

/**

515

* Get remaining path after matching.

516

* @return remaining unmatched path

517

*/

518

String remainingPath();

519

}

520

```

521

522

### Parameters Interface

523

524

Interface for accessing query and path parameters with type conversion.

525

526

```java { .api }

527

/**

528

* Interface for accessing parameters with type conversion.

529

*/

530

interface Parameters {

531

/**

532

* Get first parameter value.

533

* @param name parameter name

534

* @return optional parameter value

535

*/

536

Optional<String> first(String name);

537

538

/**

539

* Get all parameter values.

540

* @param name parameter name

541

* @return list of parameter values

542

*/

543

List<String> all(String name);

544

545

/**

546

* Get parameter value or default.

547

* @param name parameter name

548

* @param defaultValue default value if parameter not found

549

* @return parameter value or default

550

*/

551

String value(String name, String defaultValue);

552

553

/**

554

* Check if parameter exists.

555

* @param name parameter name

556

* @return true if parameter exists

557

*/

558

boolean contains(String name);

559

560

/**

561

* Get all parameter names.

562

* @return set of parameter names

563

*/

564

Set<String> names();

565

566

/**

567

* Convert to map.

568

* @return map of parameter names to first values

569

*/

570

Map<String, String> toMap();

571

572

/**

573

* Convert to multi-value map.

574

* @return map of parameter names to all values

575

*/

576

Map<String, List<String>> toMultiMap();

577

}

578

```

579

580

**Usage Examples:**

581

582

```java

583

Handler parameterHandler = (req, res) -> {

584

// Path parameters (from /users/{id}/posts/{postId})

585

Parameters pathParams = req.path().pathParameters();

586

String userId = pathParams.first("id").orElse("unknown");

587

String postId = pathParams.first("postId").orElse("unknown");

588

589

// Query parameters (?filter=active&tag=java&tag=web)

590

Parameters queryParams = req.query();

591

String filter = queryParams.value("filter", "all");

592

List<String> tags = queryParams.all("tag");

593

boolean hasSearch = queryParams.contains("search");

594

595

// Convert to maps for easier processing

596

Map<String, String> pathMap = pathParams.toMap();

597

Map<String, List<String>> queryMap = queryParams.toMultiMap();

598

599

String response = String.format(

600

"User: %s, Post: %s, Filter: %s, Tags: %s",

601

userId, postId, filter, tags

602

);

603

604

res.send(response);

605

};

606

```

607

608

## Advanced Request/Response Patterns

609

610

### Content Negotiation

611

612

```java

613

Handler contentNegotiationHandler = (req, res) -> {

614

Optional<String> acceptHeader = req.headers().first("Accept");

615

616

Map<String, Object> data = Map.of(

617

"message", "Hello World",

618

"timestamp", System.currentTimeMillis()

619

);

620

621

if (acceptHeader.isPresent()) {

622

String accept = acceptHeader.get();

623

624

if (accept.contains("application/json")) {

625

res.contentType(MediaType.APPLICATION_JSON).send(data);

626

} else if (accept.contains("application/xml")) {

627

res.contentType(MediaType.APPLICATION_XML).send(toXml(data));

628

} else if (accept.contains("text/html")) {

629

res.contentType(MediaType.TEXT_HTML)

630

.send("<h1>Hello World</h1><p>Timestamp: " + data.get("timestamp") + "</p>");

631

} else {

632

res.contentType(MediaType.TEXT_PLAIN)

633

.send("Hello World at " + data.get("timestamp"));

634

}

635

} else {

636

// Default to JSON

637

res.contentType(MediaType.APPLICATION_JSON).send(data);

638

}

639

};

640

```

641

642

### Request Validation

643

644

```java

645

Handler validationHandler = (req, res) -> {

646

// Validate required headers

647

if (!req.headers().contains("Authorization")) {

648

res.status(Status.UNAUTHORIZED_401)

649

.send("Authorization header required");

650

return;

651

}

652

653

// Validate path parameters

654

String id = req.path().pathParameters().first("id").orElse("");

655

if (id.isEmpty() || !id.matches("\\d+")) {

656

res.status(Status.BAD_REQUEST_400)

657

.send("Invalid ID parameter");

658

return;

659

}

660

661

// Validate query parameters

662

Optional<String> limit = req.query().first("limit");

663

if (limit.isPresent()) {

664

try {

665

int limitValue = Integer.parseInt(limit.get());

666

if (limitValue < 1 || limitValue > 100) {

667

res.status(Status.BAD_REQUEST_400)

668

.send("Limit must be between 1 and 100");

669

return;

670

}

671

} catch (NumberFormatException e) {

672

res.status(Status.BAD_REQUEST_400)

673

.send("Invalid limit parameter");

674

return;

675

}

676

}

677

678

// Process valid request

679

res.send("Valid request processed");

680

};

681

```

682

683

### Response Streaming

684

685

```java

686

Handler streamingHandler = (req, res) -> {

687

res.status(Status.OK_200)

688

.contentType(MediaType.TEXT_PLAIN)

689

.header("Transfer-Encoding", "chunked");

690

691

// Stream large dataset

692

try (BufferedWriter writer = new BufferedWriter(

693

new OutputStreamWriter(res.outputStream()))) {

694

695

for (int i = 0; i < 1000; i++) {

696

writer.write("Data chunk " + i + "\n");

697

writer.flush();

698

699

// Simulate processing delay

700

Thread.sleep(10);

701

}

702

} catch (Exception e) {

703

// Handle streaming errors

704

res.status(Status.INTERNAL_SERVER_ERROR_500)

705

.send("Streaming error");

706

}

707

};

708

```

709

710

### Request Context and State

711

712

```java

713

Handler contextHandler = (req, res) -> {

714

Context requestContext = req.context();

715

716

// Store data in request context

717

requestContext.register("startTime", System.currentTimeMillis());

718

requestContext.register("requestId", UUID.randomUUID().toString());

719

720

// Access context data

721

String requestId = requestContext.get("requestId", String.class)

722

.orElse("unknown");

723

724

res.header("X-Request-ID", requestId)

725

.send("Request processed with ID: " + requestId);

726

};

727

```