or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdcore-annotations.mdindex.mdresponses.mdschema-media.mdsecurity.mdservers-tags.md

responses.mddocs/

0

# Response Documentation

1

2

This document covers annotations for documenting API responses, including status codes, headers, content types, and comprehensive response scenarios.

3

4

## Imports

5

6

```java { .api }

7

import io.swagger.v3.oas.annotations.responses.ApiResponse;

8

import io.swagger.v3.oas.annotations.responses.ApiResponses;

9

import io.swagger.v3.oas.annotations.headers.Header;

10

import io.swagger.v3.oas.annotations.links.Link;

11

import io.swagger.v3.oas.annotations.links.LinkParameter;

12

import io.swagger.v3.oas.annotations.media.Content;

13

import io.swagger.v3.oas.annotations.media.Schema;

14

import io.swagger.v3.oas.annotations.media.ExampleObject;

15

```

16

17

## ApiResponse

18

19

Defines comprehensive operation response documentation including status codes, descriptions, headers, content types, and links to related operations.

20

21

### Basic Response Documentation

22

23

```java { .api }

24

@GetMapping("/pets/{id}")

25

@Operation(summary = "Get pet by ID", tags = {"pets"})

26

@ApiResponse(

27

responseCode = "200",

28

description = "Successful operation - Pet found and returned",

29

headers = {

30

@Header(

31

name = "X-Rate-Limit-Remaining",

32

description = "Number of requests remaining in current time window",

33

schema = @Schema(type = "integer", minimum = "0")

34

),

35

@Header(

36

name = "X-Rate-Limit-Reset",

37

description = "Time when rate limit resets (Unix timestamp)",

38

schema = @Schema(type = "integer", format = "int64")

39

)

40

},

41

content = @Content(

42

mediaType = "application/json",

43

schema = @Schema(implementation = Pet.class),

44

examples = {

45

@ExampleObject(

46

name = "successfulPetResponse",

47

summary = "Successful pet retrieval",

48

description = "Example of a successfully retrieved pet",

49

value = """

50

{

51

"id": 123,

52

"name": "Fluffy",

53

"category": {

54

"id": 1,

55

"name": "Dogs"

56

},

57

"status": "available",

58

"tags": ["friendly", "trained"],

59

"photoUrls": ["https://example.com/photos/fluffy.jpg"]

60

}

61

"""

62

)

63

}

64

)

65

)

66

@ApiResponse(

67

responseCode = "400",

68

description = "Invalid pet ID supplied - ID must be a positive integer",

69

content = @Content(

70

mediaType = "application/json",

71

schema = @Schema(implementation = ErrorResponse.class),

72

examples = @ExampleObject(

73

name = "invalidIdError",

74

summary = "Invalid ID error",

75

value = """

76

{

77

"error": "INVALID_PARAMETER",

78

"message": "Pet ID must be a positive integer",

79

"field": "id",

80

"code": 400

81

}

82

"""

83

)

84

)

85

)

86

@ApiResponse(

87

responseCode = "404",

88

description = "Pet not found - No pet exists with the provided ID",

89

content = @Content(

90

mediaType = "application/json",

91

schema = @Schema(implementation = ErrorResponse.class),

92

examples = @ExampleObject(

93

name = "petNotFoundError",

94

summary = "Pet not found error",

95

value = """

96

{

97

"error": "RESOURCE_NOT_FOUND",

98

"message": "No pet found with ID 123",

99

"resourceType": "Pet",

100

"resourceId": "123",

101

"code": 404

102

}

103

"""

104

)

105

)

106

)

107

public ResponseEntity<Pet> getPetById(@PathVariable Long id) {

108

Pet pet = petService.findById(id);

109

return ResponseEntity.ok()

110

.header("X-Rate-Limit-Remaining", "99")

111

.header("X-Rate-Limit-Reset", String.valueOf(System.currentTimeMillis() + 3600000))

112

.body(pet);

113

}

114

```

115

116

### Multiple Content Types

117

118

```java { .api }

119

@GetMapping(value = "/pets/{id}", produces = {"application/json", "application/xml", "text/plain"})

120

@ApiResponse(

121

responseCode = "200",

122

description = "Pet information in requested format",

123

content = {

124

@Content(

125

mediaType = "application/json",

126

schema = @Schema(implementation = Pet.class),

127

examples = @ExampleObject(

128

name = "jsonPet",

129

value = "{ \"id\": 1, \"name\": \"Fluffy\", \"status\": \"available\" }"

130

)

131

),

132

@Content(

133

mediaType = "application/xml",

134

schema = @Schema(implementation = Pet.class),

135

examples = @ExampleObject(

136

name = "xmlPet",

137

value = "<pet><id>1</id><name>Fluffy</name><status>available</status></pet>"

138

)

139

),

140

@Content(

141

mediaType = "text/plain",

142

schema = @Schema(type = "string"),

143

examples = @ExampleObject(

144

name = "textPet",

145

value = "Pet ID: 1, Name: Fluffy, Status: available"

146

)

147

)

148

}

149

)

150

```

151

152

### Response with Links

153

154

```java { .api }

155

@PostMapping("/pets")

156

@ApiResponse(

157

responseCode = "201",

158

description = "Pet created successfully",

159

headers = @Header(

160

name = "Location",

161

description = "URL of the newly created pet resource",

162

schema = @Schema(type = "string", format = "uri")

163

),

164

content = @Content(

165

mediaType = "application/json",

166

schema = @Schema(implementation = Pet.class)

167

),

168

links = {

169

@Link(

170

name = "GetPetById",

171

description = "Link to retrieve the created pet",

172

operationId = "getPetById",

173

parameters = @LinkParameter(

174

name = "id",

175

expression = "$response.body#/id"

176

)

177

),

178

@Link(

179

name = "UpdatePet",

180

description = "Link to update the created pet",

181

operationId = "updatePet",

182

parameters = @LinkParameter(

183

name = "id",

184

expression = "$response.body#/id"

185

)

186

),

187

@Link(

188

name = "DeletePet",

189

description = "Link to delete the created pet",

190

operationId = "deletePet",

191

parameters = @LinkParameter(

192

name = "id",

193

expression = "$response.body#/id"

194

)

195

)

196

}

197

)

198

```

199

200

### Conditional Response Documentation

201

202

```java { .api }

203

@PutMapping("/pets/{id}")

204

@ApiResponse(

205

responseCode = "200",

206

description = "Pet updated successfully",

207

content = @Content(

208

mediaType = "application/json",

209

schema = @Schema(implementation = Pet.class)

210

)

211

)

212

@ApiResponse(

213

responseCode = "201",

214

description = "Pet created (ID did not exist)",

215

headers = @Header(

216

name = "Location",

217

description = "URL of the newly created pet",

218

schema = @Schema(type = "string", format = "uri")

219

),

220

content = @Content(

221

mediaType = "application/json",

222

schema = @Schema(implementation = Pet.class)

223

)

224

)

225

@ApiResponse(

226

responseCode = "400",

227

description = "Invalid request data",

228

content = @Content(

229

mediaType = "application/json",

230

schema = @Schema(implementation = ValidationErrorResponse.class)

231

)

232

)

233

```

234

235

### Response with Custom Headers

236

237

```java { .api }

238

@GetMapping("/pets")

239

@ApiResponse(

240

responseCode = "200",

241

description = "List of pets retrieved successfully",

242

headers = {

243

@Header(

244

name = "X-Total-Count",

245

description = "Total number of pets available",

246

schema = @Schema(type = "integer", minimum = "0"),

247

example = "150"

248

),

249

@Header(

250

name = "X-Page-Count",

251

description = "Total number of pages available",

252

schema = @Schema(type = "integer", minimum = "1"),

253

example = "8"

254

),

255

@Header(

256

name = "X-Per-Page",

257

description = "Number of items per page",

258

schema = @Schema(type = "integer", minimum = "1", maximum = "100"),

259

example = "20"

260

),

261

@Header(

262

name = "X-Current-Page",

263

description = "Current page number",

264

schema = @Schema(type = "integer", minimum = "1"),

265

example = "1"

266

),

267

@Header(

268

name = "Link",

269

description = "Pagination links (RFC 5988)",

270

schema = @Schema(type = "string"),

271

example = "<https://api.petstore.io/pets?page=2>; rel=\"next\", <https://api.petstore.io/pets?page=8>; rel=\"last\""

272

)

273

},

274

content = @Content(

275

mediaType = "application/json",

276

schema = @Schema(implementation = PetListResponse.class)

277

)

278

)

279

```

280

281

### ApiResponse Attributes

282

283

```java { .api }

284

public @interface ApiResponse {

285

String description() default "";

286

String responseCode() default "default";

287

Header[] headers() default {};

288

Link[] links() default {};

289

Content[] content() default {};

290

Extension[] extensions() default {};

291

String ref() default "";

292

boolean useReturnTypeSchema() default false;

293

}

294

```

295

296

## ApiResponses

297

298

Container annotation for multiple response scenarios, allowing comprehensive documentation of all possible operation outcomes.

299

300

### Complete Response Documentation

301

302

```java { .api }

303

@PostMapping("/pets")

304

@Operation(summary = "Create a new pet", tags = {"pets"})

305

@ApiResponses({

306

@ApiResponse(

307

responseCode = "201",

308

description = "Pet created successfully",

309

headers = @Header(

310

name = "Location",

311

description = "URI of the created pet resource",

312

schema = @Schema(type = "string", format = "uri")

313

),

314

content = @Content(

315

mediaType = "application/json",

316

schema = @Schema(implementation = Pet.class),

317

examples = @ExampleObject(

318

name = "createdPet",

319

summary = "Successfully created pet",

320

value = """

321

{

322

"id": 124,

323

"name": "New Pet",

324

"category": {"id": 1, "name": "Dogs"},

325

"status": "available"

326

}

327

"""

328

)

329

),

330

links = @Link(

331

name = "GetCreatedPet",

332

operationId = "getPetById",

333

parameters = @LinkParameter(name = "id", expression = "$response.body#/id")

334

)

335

),

336

@ApiResponse(

337

responseCode = "400",

338

description = "Invalid input data provided",

339

content = @Content(

340

mediaType = "application/json",

341

schema = @Schema(implementation = ValidationErrorResponse.class),

342

examples = {

343

@ExampleObject(

344

name = "missingRequiredFields",

345

summary = "Missing required fields",

346

description = "Error when required fields are not provided",

347

value = """

348

{

349

"error": "VALIDATION_ERROR",

350

"message": "Required fields are missing",

351

"violations": [

352

{

353

"field": "name",

354

"message": "Pet name is required"

355

},

356

{

357

"field": "status",

358

"message": "Pet status must be specified"

359

}

360

]

361

}

362

"""

363

),

364

@ExampleObject(

365

name = "invalidFieldValues",

366

summary = "Invalid field values",

367

description = "Error when field values don't meet constraints",

368

value = """

369

{

370

"error": "VALIDATION_ERROR",

371

"message": "Invalid field values provided",

372

"violations": [

373

{

374

"field": "name",

375

"message": "Pet name must be between 1 and 50 characters"

376

},

377

{

378

"field": "status",

379

"message": "Status must be one of: available, pending, sold"

380

}

381

]

382

}

383

"""

384

)

385

}

386

)

387

),

388

@ApiResponse(

389

responseCode = "401",

390

description = "Authentication required - Invalid or missing API key",

391

headers = @Header(

392

name = "WWW-Authenticate",

393

description = "Authentication method required",

394

schema = @Schema(type = "string", defaultValue = "ApiKey")

395

),

396

content = @Content(

397

mediaType = "application/json",

398

schema = @Schema(implementation = ErrorResponse.class),

399

examples = @ExampleObject(

400

name = "authenticationError",

401

value = """

402

{

403

"error": "AUTHENTICATION_REQUIRED",

404

"message": "Valid API key is required",

405

"code": 401

406

}

407

"""

408

)

409

)

410

),

411

@ApiResponse(

412

responseCode = "403",

413

description = "Insufficient permissions - User cannot create pets",

414

content = @Content(

415

mediaType = "application/json",

416

schema = @Schema(implementation = ErrorResponse.class),

417

examples = @ExampleObject(

418

name = "permissionError",

419

value = """

420

{

421

"error": "INSUFFICIENT_PERMISSIONS",

422

"message": "User does not have permission to create pets",

423

"requiredPermission": "pets:create",

424

"code": 403

425

}

426

"""

427

)

428

)

429

),

430

@ApiResponse(

431

responseCode = "409",

432

description = "Conflict - Pet with same name already exists",

433

content = @Content(

434

mediaType = "application/json",

435

schema = @Schema(implementation = ConflictErrorResponse.class),

436

examples = @ExampleObject(

437

name = "conflictError",

438

value = """

439

{

440

"error": "RESOURCE_CONFLICT",

441

"message": "A pet with this name already exists",

442

"conflictField": "name",

443

"conflictValue": "Fluffy",

444

"existingResourceId": 123,

445

"code": 409

446

}

447

"""

448

)

449

)

450

),

451

@ApiResponse(

452

responseCode = "422",

453

description = "Unprocessable Entity - Request data fails business rules",

454

content = @Content(

455

mediaType = "application/json",

456

schema = @Schema(implementation = BusinessRuleErrorResponse.class),

457

examples = @ExampleObject(

458

name = "businessRuleError",

459

value = """

460

{

461

"error": "BUSINESS_RULE_VIOLATION",

462

"message": "Cannot create pet: Maximum pet limit reached for this user",

463

"rule": "MAX_PETS_PER_USER",

464

"limit": 10,

465

"current": 10,

466

"code": 422

467

}

468

"""

469

)

470

)

471

),

472

@ApiResponse(

473

responseCode = "429",

474

description = "Too Many Requests - Rate limit exceeded",

475

headers = {

476

@Header(

477

name = "X-Rate-Limit-Limit",

478

description = "Request limit per time window",

479

schema = @Schema(type = "integer")

480

),

481

@Header(

482

name = "X-Rate-Limit-Remaining",

483

description = "Remaining requests in current window",

484

schema = @Schema(type = "integer")

485

),

486

@Header(

487

name = "X-Rate-Limit-Reset",

488

description = "Time when rate limit resets",

489

schema = @Schema(type = "integer", format = "int64")

490

),

491

@Header(

492

name = "Retry-After",

493

description = "Seconds to wait before retrying",

494

schema = @Schema(type = "integer")

495

)

496

},

497

content = @Content(

498

mediaType = "application/json",

499

schema = @Schema(implementation = RateLimitErrorResponse.class),

500

examples = @ExampleObject(

501

name = "rateLimitError",

502

value = """

503

{

504

"error": "RATE_LIMIT_EXCEEDED",

505

"message": "Too many requests. Rate limit exceeded.",

506

"retryAfter": 60,

507

"code": 429

508

}

509

"""

510

)

511

)

512

),

513

@ApiResponse(

514

responseCode = "500",

515

description = "Internal Server Error - Unexpected server error occurred",

516

content = @Content(

517

mediaType = "application/json",

518

schema = @Schema(implementation = ErrorResponse.class),

519

examples = @ExampleObject(

520

name = "serverError",

521

value = """

522

{

523

"error": "INTERNAL_SERVER_ERROR",

524

"message": "An unexpected error occurred while processing the request",

525

"traceId": "abc123def456",

526

"code": 500

527

}

528

"""

529

)

530

)

531

)

532

})

533

public ResponseEntity<Pet> createPet(@Valid @RequestBody CreatePetRequest request) {

534

Pet createdPet = petService.create(request);

535

URI location = ServletUriComponentsBuilder

536

.fromCurrentRequest()

537

.path("/{id}")

538

.buildAndExpand(createdPet.getId())

539

.toUri();

540

541

return ResponseEntity.created(location).body(createdPet);

542

}

543

```

544

545

### Async Operation Responses

546

547

```java { .api }

548

@PostMapping("/pets/{id}/process")

549

@ApiResponses({

550

@ApiResponse(

551

responseCode = "202",

552

description = "Processing started - Operation accepted for asynchronous processing",

553

headers = {

554

@Header(

555

name = "Location",

556

description = "URL to check processing status",

557

schema = @Schema(type = "string", format = "uri")

558

),

559

@Header(

560

name = "X-Process-ID",

561

description = "Unique identifier for the processing job",

562

schema = @Schema(type = "string", format = "uuid")

563

)

564

},

565

content = @Content(

566

mediaType = "application/json",

567

schema = @Schema(implementation = ProcessingResponse.class),

568

examples = @ExampleObject(

569

name = "processingStarted",

570

value = """

571

{

572

"processId": "123e4567-e89b-12d3-a456-426614174000",

573

"status": "processing",

574

"message": "Pet processing has been started",

575

"estimatedCompletion": "2024-01-15T10:30:00Z",

576

"statusUrl": "/api/v1/processes/123e4567-e89b-12d3-a456-426614174000"

577

}

578

"""

579

)

580

),

581

links = {

582

@Link(

583

name = "CheckStatus",

584

description = "Check processing status",

585

operationId = "getProcessStatus",

586

parameters = @LinkParameter(

587

name = "processId",

588

expression = "$response.body#/processId"

589

)

590

),

591

@Link(

592

name = "CancelProcess",

593

description = "Cancel the processing job",

594

operationId = "cancelProcess",

595

parameters = @LinkParameter(

596

name = "processId",

597

expression = "$response.body#/processId"

598

)

599

)

600

}

601

),

602

@ApiResponse(

603

responseCode = "303",

604

description = "See Other - Processing already completed, redirect to result",

605

headers = @Header(

606

name = "Location",

607

description = "URL of the completed processing result",

608

schema = @Schema(type = "string", format = "uri")

609

)

610

)

611

})

612

```

613

614

### Bulk Operation Responses

615

616

```java { .api }

617

@PostMapping("/pets/bulk")

618

@ApiResponses({

619

@ApiResponse(

620

responseCode = "207",

621

description = "Multi-Status - Partial success with mixed results",

622

content = @Content(

623

mediaType = "application/json",

624

schema = @Schema(implementation = BulkOperationResponse.class),

625

examples = @ExampleObject(

626

name = "partialSuccess",

627

summary = "Partial success example",

628

description = "Some pets created successfully, others failed",

629

value = """

630

{

631

"overallStatus": "partial_success",

632

"totalRequests": 5,

633

"successCount": 3,

634

"failureCount": 2,

635

"results": [

636

{

637

"index": 0,

638

"status": 201,

639

"success": true,

640

"data": {"id": 101, "name": "Pet1", "status": "available"}

641

},

642

{

643

"index": 1,

644

"status": 400,

645

"success": false,

646

"error": {"message": "Invalid pet name", "field": "name"}

647

},

648

{

649

"index": 2,

650

"status": 201,

651

"success": true,

652

"data": {"id": 102, "name": "Pet2", "status": "available"}

653

},

654

{

655

"index": 3,

656

"status": 409,

657

"success": false,

658

"error": {"message": "Pet name already exists", "conflictField": "name"}

659

},

660

{

661

"index": 4,

662

"status": 201,

663

"success": true,

664

"data": {"id": 103, "name": "Pet3", "status": "available"}

665

}

666

]

667

}

668

"""

669

)

670

)

671

),

672

@ApiResponse(

673

responseCode = "200",

674

description = "All operations completed successfully",

675

content = @Content(

676

mediaType = "application/json",

677

schema = @Schema(implementation = BulkOperationResponse.class)

678

)

679

),

680

@ApiResponse(

681

responseCode = "400",

682

description = "All operations failed due to invalid input",

683

content = @Content(

684

mediaType = "application/json",

685

schema = @Schema(implementation = BulkOperationResponse.class)

686

)

687

)

688

})

689

```

690

691

### File Download Responses

692

693

```java { .api }

694

@GetMapping("/pets/{id}/photo")

695

@ApiResponses({

696

@ApiResponse(

697

responseCode = "200",

698

description = "Pet photo download",

699

headers = {

700

@Header(

701

name = "Content-Type",

702

description = "Image media type",

703

schema = @Schema(type = "string", allowableValues = {"image/jpeg", "image/png", "image/gif"})

704

),

705

@Header(

706

name = "Content-Length",

707

description = "File size in bytes",

708

schema = @Schema(type = "integer", minimum = "0")

709

),

710

@Header(

711

name = "Content-Disposition",

712

description = "File download disposition",

713

schema = @Schema(type = "string"),

714

example = "attachment; filename=\"pet-123-photo.jpg\""

715

),

716

@Header(

717

name = "Cache-Control",

718

description = "Cache control directives",

719

schema = @Schema(type = "string"),

720

example = "public, max-age=3600"

721

),

722

@Header(

723

name = "ETag",

724

description = "Entity tag for caching",

725

schema = @Schema(type = "string"),

726

example = "\"abc123def456\""

727

),

728

@Header(

729

name = "Last-Modified",

730

description = "Last modification date",

731

schema = @Schema(type = "string", format = "date-time")

732

)

733

},

734

content = {

735

@Content(mediaType = "image/jpeg", schema = @Schema(type = "string", format = "binary")),

736

@Content(mediaType = "image/png", schema = @Schema(type = "string", format = "binary")),

737

@Content(mediaType = "image/gif", schema = @Schema(type = "string", format = "binary"))

738

}

739

),

740

@ApiResponse(

741

responseCode = "304",

742

description = "Not Modified - Photo has not changed since last request",

743

headers = {

744

@Header(

745

name = "Cache-Control",

746

schema = @Schema(type = "string")

747

),

748

@Header(

749

name = "ETag",

750

schema = @Schema(type = "string")

751

)

752

}

753

),

754

@ApiResponse(

755

responseCode = "404",

756

description = "Photo not found for this pet"

757

)

758

})

759

```

760

761

### ApiResponses Attributes

762

763

```java { .api }

764

public @interface ApiResponses {

765

ApiResponse[] value() default {};

766

}

767

```

768

769

## Response Model Examples

770

771

### Error Response Models

772

773

```java { .api }

774

@Schema(description = "Standard error response")

775

public class ErrorResponse {

776

@Schema(description = "Error code identifier", example = "RESOURCE_NOT_FOUND")

777

private String error;

778

779

@Schema(description = "Human-readable error message", example = "The requested resource was not found")

780

private String message;

781

782

@Schema(description = "HTTP status code", example = "404")

783

private Integer code;

784

785

@Schema(description = "Request trace ID for debugging", example = "abc123def456")

786

private String traceId;

787

788

@Schema(description = "Timestamp of the error", format = "date-time")

789

private Instant timestamp;

790

}

791

792

@Schema(description = "Validation error response with field-level details")

793

public class ValidationErrorResponse extends ErrorResponse {

794

@Schema(description = "List of field validation violations")

795

private List<FieldViolation> violations;

796

797

@Schema(description = "Field validation violation details")

798

public static class FieldViolation {

799

@Schema(description = "Field name that failed validation", example = "name")

800

private String field;

801

802

@Schema(description = "Validation failure message", example = "must not be blank")

803

private String message;

804

805

@Schema(description = "Rejected value", example = "")

806

private Object rejectedValue;

807

}

808

}

809

```