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
```