0
# Response Documentation
1
2
Annotations for documenting API responses, status codes, and response headers. These annotations provide detailed metadata about what clients can expect when calling API endpoints, including success and error scenarios.
3
4
## Capabilities
5
6
### @ApiResponse Annotation
7
8
Documents a single response from an operation, including the response code, message, and return type.
9
10
```java { .api }
11
/**
12
* Documents a single response from an operation
13
* Target: METHOD, TYPE
14
* Retention: RUNTIME
15
*/
16
@Target({ElementType.METHOD, ElementType.TYPE})
17
@Retention(RetentionPolicy.RUNTIME)
18
@interface ApiResponse {
19
/**
20
* Response code (HTTP status code)
21
* REQUIRED ATTRIBUTE
22
* Should use formal HTTP Status Code definitions
23
*/
24
int code();
25
26
/**
27
* Human-readable response message
28
* REQUIRED ATTRIBUTE
29
* Brief description of what this response means
30
*/
31
String message();
32
33
/**
34
* Optional response class
35
* Describes the type of response body
36
* Default Void.class means no response body
37
*/
38
Class<?> response() default Void.class;
39
40
/**
41
* Specifies a reference to response type definition
42
* Can be local or remote reference
43
* Overrides response() class if specified
44
*/
45
String reference() default "";
46
47
/**
48
* List of possible headers for this response
49
*/
50
ResponseHeader[] responseHeaders() default @ResponseHeader(name = "", response = Void.class);
51
52
/**
53
* Declares container wrapping the response
54
* Valid values: "List", "Set", "Map"
55
* Other values are ignored
56
*/
57
String responseContainer() default "";
58
}
59
```
60
61
**Usage Examples:**
62
63
```java
64
// Single response documentation
65
@ApiResponse(code = 200, message = "User found", response = User.class)
66
@GET
67
@Path("/{id}")
68
public User getUser(@PathParam("id") Long id) {
69
// implementation
70
}
71
72
// Response with headers
73
@ApiResponse(
74
code = 201,
75
message = "User created successfully",
76
response = User.class,
77
responseHeaders = {
78
@ResponseHeader(
79
name = "Location",
80
description = "URL of the created user",
81
response = String.class
82
)
83
}
84
)
85
@POST
86
public Response createUser(User user) {
87
// implementation
88
}
89
90
// Collection response
91
@ApiResponse(
92
code = 200,
93
message = "Users retrieved successfully",
94
response = User.class,
95
responseContainer = "List"
96
)
97
@GET
98
public List<User> getAllUsers() {
99
// implementation
100
}
101
```
102
103
### @ApiResponses Annotation
104
105
Container annotation for documenting multiple possible responses from a single operation.
106
107
```java { .api }
108
/**
109
* Container for multiple @ApiResponse annotations
110
* Target: ANNOTATION_TYPE, METHOD, TYPE
111
* Retention: RUNTIME
112
*/
113
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE})
114
@Retention(RetentionPolicy.RUNTIME)
115
@interface ApiResponses {
116
/** Array of response definitions */
117
ApiResponse[] value();
118
}
119
```
120
121
**Usage Examples:**
122
123
```java
124
// Multiple response scenarios
125
@ApiResponses({
126
@ApiResponse(code = 200, message = "User found", response = User.class),
127
@ApiResponse(code = 404, message = "User not found"),
128
@ApiResponse(code = 500, message = "Internal server error")
129
})
130
@GET
131
@Path("/{id}")
132
public Response getUser(@PathParam("id") Long id) {
133
// implementation
134
}
135
136
// CRUD operation with full response documentation
137
@ApiResponses({
138
@ApiResponse(
139
code = 201,
140
message = "User created successfully",
141
response = User.class,
142
responseHeaders = @ResponseHeader(name = "Location", response = String.class)
143
),
144
@ApiResponse(code = 400, message = "Invalid user data", response = ErrorResponse.class),
145
@ApiResponse(code = 409, message = "User already exists", response = ErrorResponse.class),
146
@ApiResponse(code = 500, message = "Internal server error", response = ErrorResponse.class)
147
})
148
@POST
149
public Response createUser(User user) {
150
// implementation
151
}
152
153
// Search operation with various outcomes
154
@ApiResponses({
155
@ApiResponse(
156
code = 200,
157
message = "Search completed successfully",
158
response = User.class,
159
responseContainer = "List"
160
),
161
@ApiResponse(code = 204, message = "No users found matching criteria"),
162
@ApiResponse(code = 400, message = "Invalid search parameters", response = ErrorResponse.class),
163
@ApiResponse(code = 429, message = "Rate limit exceeded",
164
responseHeaders = @ResponseHeader(name = "Retry-After", response = Integer.class))
165
})
166
@GET
167
@Path("/search")
168
public Response searchUsers(
169
@QueryParam("q") String query,
170
@QueryParam("limit") Integer limit
171
) {
172
// implementation
173
}
174
```
175
176
### @ResponseHeader Annotation
177
178
Documents headers that may be returned with a response.
179
180
```java { .api }
181
/**
182
* Documents a response header
183
* Target: ANNOTATION_TYPE (used within other annotations)
184
* Retention: RUNTIME
185
*/
186
@Target(ElementType.ANNOTATION_TYPE)
187
@Retention(RetentionPolicy.RUNTIME)
188
@interface ResponseHeader {
189
/**
190
* Name of the response header
191
* REQUIRED ATTRIBUTE
192
*/
193
String name();
194
195
/** Description of the header */
196
String description() default "";
197
198
/**
199
* Response type/class for the header value
200
* REQUIRED ATTRIBUTE
201
*/
202
Class<?> response();
203
204
/**
205
* Container type for the header if it contains multiple values
206
* Valid values: "List", "Set", "Map"
207
*/
208
String responseContainer() default "";
209
}
210
```
211
212
**Usage Examples:**
213
214
```java
215
// Authentication response with token in header
216
@ApiResponse(
217
code = 200,
218
message = "Login successful",
219
response = User.class,
220
responseHeaders = {
221
@ResponseHeader(
222
name = "Authorization",
223
description = "JWT token for subsequent requests",
224
response = String.class
225
),
226
@ResponseHeader(
227
name = "X-Token-Expires",
228
description = "Token expiration timestamp",
229
response = Long.class
230
)
231
}
232
)
233
@POST
234
@Path("/login")
235
public Response login(LoginRequest request) {
236
// implementation
237
}
238
239
// File download with metadata headers
240
@ApiResponse(
241
code = 200,
242
message = "File downloaded successfully",
243
responseHeaders = {
244
@ResponseHeader(
245
name = "Content-Type",
246
description = "MIME type of the file",
247
response = String.class
248
),
249
@ResponseHeader(
250
name = "Content-Length",
251
description = "Size of file in bytes",
252
response = Long.class
253
),
254
@ResponseHeader(
255
name = "Content-Disposition",
256
description = "Attachment filename",
257
response = String.class
258
),
259
@ResponseHeader(
260
name = "Last-Modified",
261
description = "File modification timestamp",
262
response = String.class
263
)
264
}
265
)
266
@GET
267
@Path("/files/{id}/download")
268
public Response downloadFile(@PathParam("id") String fileId) {
269
// implementation
270
}
271
272
// Pagination headers
273
@ApiResponse(
274
code = 200,
275
message = "Page retrieved successfully",
276
response = User.class,
277
responseContainer = "List",
278
responseHeaders = {
279
@ResponseHeader(
280
name = "X-Total-Count",
281
description = "Total number of items available",
282
response = Integer.class
283
),
284
@ResponseHeader(
285
name = "X-Page-Count",
286
description = "Total number of pages",
287
response = Integer.class
288
),
289
@ResponseHeader(
290
name = "Link",
291
description = "Links to first, last, next, and previous pages",
292
response = String.class
293
)
294
}
295
)
296
@GET
297
public Response getUsers(
298
@QueryParam("page") @DefaultValue("1") Integer page,
299
@QueryParam("size") @DefaultValue("20") Integer size
300
) {
301
// implementation
302
}
303
```
304
305
### Common Response Patterns
306
307
#### REST CRUD Operations
308
309
```java
310
@Path("/users")
311
public class UserController {
312
313
// GET collection
314
@ApiResponses({
315
@ApiResponse(
316
code = 200,
317
message = "Users retrieved successfully",
318
response = User.class,
319
responseContainer = "List",
320
responseHeaders = @ResponseHeader(name = "X-Total-Count", response = Integer.class)
321
),
322
@ApiResponse(code = 204, message = "No users found")
323
})
324
@GET
325
public Response getAllUsers() {
326
// implementation
327
}
328
329
// GET single resource
330
@ApiResponses({
331
@ApiResponse(code = 200, message = "User found", response = User.class),
332
@ApiResponse(code = 404, message = "User not found", response = ErrorResponse.class)
333
})
334
@GET
335
@Path("/{id}")
336
public Response getUser(@PathParam("id") Long id) {
337
// implementation
338
}
339
340
// POST create
341
@ApiResponses({
342
@ApiResponse(
343
code = 201,
344
message = "User created successfully",
345
response = User.class,
346
responseHeaders = @ResponseHeader(name = "Location", response = String.class)
347
),
348
@ApiResponse(code = 400, message = "Invalid user data", response = ErrorResponse.class),
349
@ApiResponse(code = 409, message = "User already exists", response = ErrorResponse.class)
350
})
351
@POST
352
public Response createUser(User user) {
353
// implementation
354
}
355
356
// PUT update
357
@ApiResponses({
358
@ApiResponse(code = 200, message = "User updated successfully", response = User.class),
359
@ApiResponse(code = 404, message = "User not found", response = ErrorResponse.class),
360
@ApiResponse(code = 400, message = "Invalid user data", response = ErrorResponse.class)
361
})
362
@PUT
363
@Path("/{id}")
364
public Response updateUser(@PathParam("id") Long id, User user) {
365
// implementation
366
}
367
368
// DELETE
369
@ApiResponses({
370
@ApiResponse(code = 204, message = "User deleted successfully"),
371
@ApiResponse(code = 404, message = "User not found", response = ErrorResponse.class),
372
@ApiResponse(code = 409, message = "Cannot delete user with active dependencies", response = ErrorResponse.class)
373
})
374
@DELETE
375
@Path("/{id}")
376
public Response deleteUser(@PathParam("id") Long id) {
377
// implementation
378
}
379
}
380
```
381
382
#### Error Response Models
383
384
```java
385
@ApiModel(description = "Standard error response")
386
public class ErrorResponse {
387
388
@ApiModelProperty(value = "Error code", required = true, example = "VALIDATION_ERROR")
389
private String code;
390
391
@ApiModelProperty(value = "Human-readable error message", required = true, example = "Invalid input data")
392
private String message;
393
394
@ApiModelProperty(value = "Request timestamp", example = "2023-01-15T10:30:00Z")
395
private LocalDateTime timestamp;
396
397
@ApiModelProperty(value = "Request path", example = "/api/users")
398
private String path;
399
400
@ApiModelProperty(value = "Validation errors")
401
private List<FieldError> fieldErrors;
402
}
403
404
@ApiModel(description = "Field validation error")
405
public class FieldError {
406
407
@ApiModelProperty(value = "Field name", example = "email")
408
private String field;
409
410
@ApiModelProperty(value = "Rejected value", example = "invalid-email")
411
private Object rejectedValue;
412
413
@ApiModelProperty(value = "Error message", example = "Must be a valid email address")
414
private String message;
415
}
416
```
417
418
#### Async and Long-Running Operations
419
420
```java
421
// Async operation initiation
422
@ApiResponses({
423
@ApiResponse(
424
code = 202,
425
message = "Processing started",
426
response = JobResponse.class,
427
responseHeaders = @ResponseHeader(name = "Location", description = "Job status URL", response = String.class)
428
),
429
@ApiResponse(code = 400, message = "Invalid request", response = ErrorResponse.class)
430
})
431
@POST
432
@Path("/bulk-import")
433
public Response startBulkImport(BulkImportRequest request) {
434
// implementation
435
}
436
437
// Job status checking
438
@ApiResponses({
439
@ApiResponse(code = 200, message = "Job status retrieved", response = JobStatus.class),
440
@ApiResponse(code = 404, message = "Job not found", response = ErrorResponse.class)
441
})
442
@GET
443
@Path("/jobs/{jobId}")
444
public Response getJobStatus(@PathParam("jobId") String jobId) {
445
// implementation
446
}
447
448
@ApiModel(description = "Background job response")
449
public class JobResponse {
450
451
@ApiModelProperty(value = "Job identifier", example = "job-12345")
452
private String jobId;
453
454
@ApiModelProperty(value = "Job status URL", example = "/api/jobs/job-12345")
455
private String statusUrl;
456
457
@ApiModelProperty(value = "Estimated completion time", example = "2023-01-15T11:00:00Z")
458
private LocalDateTime estimatedCompletion;
459
}
460
```
461
462
### File Operations
463
464
```java
465
// File upload
466
@ApiResponses({
467
@ApiResponse(
468
code = 201,
469
message = "File uploaded successfully",
470
response = FileInfo.class,
471
responseHeaders = {
472
@ResponseHeader(name = "Location", description = "File URL", response = String.class),
473
@ResponseHeader(name = "ETag", description = "File hash", response = String.class)
474
}
475
),
476
@ApiResponse(code = 400, message = "Invalid file", response = ErrorResponse.class),
477
@ApiResponse(code = 413, message = "File too large", response = ErrorResponse.class),
478
@ApiResponse(code = 415, message = "Unsupported file type", response = ErrorResponse.class)
479
})
480
@POST
481
@Path("/upload")
482
@Consumes(MediaType.MULTIPART_FORM_DATA)
483
public Response uploadFile(
484
@FormDataParam("file") InputStream fileInputStream,
485
@FormDataParam("file") FormDataContentDisposition fileDetail
486
) {
487
// implementation
488
}
489
490
// File download
491
@ApiResponses({
492
@ApiResponse(
493
code = 200,
494
message = "File content",
495
responseHeaders = {
496
@ResponseHeader(name = "Content-Type", response = String.class),
497
@ResponseHeader(name = "Content-Length", response = Long.class),
498
@ResponseHeader(name = "Content-Disposition", response = String.class)
499
}
500
),
501
@ApiResponse(code = 404, message = "File not found", response = ErrorResponse.class),
502
@ApiResponse(code = 403, message = "Access denied", response = ErrorResponse.class)
503
})
504
@GET
505
@Path("/files/{id}")
506
public Response downloadFile(@PathParam("id") String fileId) {
507
// implementation
508
}
509
```
510
511
### Best Practices
512
513
1. **Document all possible responses** - Include success, client error, and server error scenarios
514
2. **Use appropriate HTTP status codes** - Follow HTTP specification and REST conventions
515
3. **Provide meaningful messages** - Clear, human-readable descriptions of each response
516
4. **Include error response models** - Document the structure of error responses
517
5. **Document response headers** - Include important headers like Location, ETag, etc.
518
6. **Use container types** - Specify "List", "Set", or "Map" for collection responses
519
7. **Document async patterns** - Include 202 responses for long-running operations
520
8. **Consider edge cases** - Document rate limiting, validation errors, conflicts, etc.
521
9. **Be consistent** - Use consistent response patterns across your API
522
10. **Include examples** - Provide sample response bodies in your models