CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-swagger--swagger-annotations

Java annotations for defining Swagger API documentation and OpenAPI specification metadata

Pending
Overview
Eval results
Files

responses.mddocs/

Response Documentation

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.

Capabilities

@ApiResponse Annotation

Documents a single response from an operation, including the response code, message, and return type.

/**
 * Documents a single response from an operation
 * Target: METHOD, TYPE
 * Retention: RUNTIME
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface ApiResponse {
    /** 
     * Response code (HTTP status code)
     * REQUIRED ATTRIBUTE
     * Should use formal HTTP Status Code definitions
     */
    int code();
    
    /** 
     * Human-readable response message
     * REQUIRED ATTRIBUTE
     * Brief description of what this response means
     */
    String message();
    
    /** 
     * Optional response class
     * Describes the type of response body
     * Default Void.class means no response body
     */
    Class<?> response() default Void.class;
    
    /** 
     * Specifies a reference to response type definition
     * Can be local or remote reference
     * Overrides response() class if specified
     */
    String reference() default "";
    
    /** 
     * List of possible headers for this response 
     */
    ResponseHeader[] responseHeaders() default @ResponseHeader(name = "", response = Void.class);
    
    /** 
     * Declares container wrapping the response
     * Valid values: "List", "Set", "Map"
     * Other values are ignored
     */
    String responseContainer() default "";
}

Usage Examples:

// Single response documentation
@ApiResponse(code = 200, message = "User found", response = User.class)
@GET
@Path("/{id}")
public User getUser(@PathParam("id") Long id) {
    // implementation
}

// Response with headers
@ApiResponse(
    code = 201, 
    message = "User created successfully",
    response = User.class,
    responseHeaders = {
        @ResponseHeader(
            name = "Location", 
            description = "URL of the created user",
            response = String.class
        )
    }
)
@POST
public Response createUser(User user) {
    // implementation
}

// Collection response
@ApiResponse(
    code = 200,
    message = "Users retrieved successfully", 
    response = User.class,
    responseContainer = "List"
)
@GET
public List<User> getAllUsers() {
    // implementation
}

@ApiResponses Annotation

Container annotation for documenting multiple possible responses from a single operation.

/**
 * Container for multiple @ApiResponse annotations
 * Target: ANNOTATION_TYPE, METHOD, TYPE
 * Retention: RUNTIME
 */
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface ApiResponses {
    /** Array of response definitions */
    ApiResponse[] value();
}

Usage Examples:

// Multiple response scenarios
@ApiResponses({
    @ApiResponse(code = 200, message = "User found", response = User.class),
    @ApiResponse(code = 404, message = "User not found"),
    @ApiResponse(code = 500, message = "Internal server error")
})
@GET
@Path("/{id}")
public Response getUser(@PathParam("id") Long id) {
    // implementation
}

// CRUD operation with full response documentation
@ApiResponses({
    @ApiResponse(
        code = 201, 
        message = "User created successfully",
        response = User.class,
        responseHeaders = @ResponseHeader(name = "Location", response = String.class)
    ),
    @ApiResponse(code = 400, message = "Invalid user data", response = ErrorResponse.class),
    @ApiResponse(code = 409, message = "User already exists", response = ErrorResponse.class),
    @ApiResponse(code = 500, message = "Internal server error", response = ErrorResponse.class)
})
@POST
public Response createUser(User user) {
    // implementation
}

// Search operation with various outcomes
@ApiResponses({
    @ApiResponse(
        code = 200, 
        message = "Search completed successfully",
        response = User.class,
        responseContainer = "List"
    ),
    @ApiResponse(code = 204, message = "No users found matching criteria"),
    @ApiResponse(code = 400, message = "Invalid search parameters", response = ErrorResponse.class),
    @ApiResponse(code = 429, message = "Rate limit exceeded", 
                responseHeaders = @ResponseHeader(name = "Retry-After", response = Integer.class))
})
@GET
@Path("/search")
public Response searchUsers(
    @QueryParam("q") String query,
    @QueryParam("limit") Integer limit
) {
    // implementation
}

@ResponseHeader Annotation

Documents headers that may be returned with a response.

/**
 * Documents a response header
 * Target: ANNOTATION_TYPE (used within other annotations)
 * Retention: RUNTIME
 */
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface ResponseHeader {
    /** 
     * Name of the response header
     * REQUIRED ATTRIBUTE
     */
    String name();
    
    /** Description of the header */
    String description() default "";
    
    /** 
     * Response type/class for the header value
     * REQUIRED ATTRIBUTE
     */
    Class<?> response();
    
    /** 
     * Container type for the header if it contains multiple values
     * Valid values: "List", "Set", "Map"
     */
    String responseContainer() default "";
}

Usage Examples:

// Authentication response with token in header
@ApiResponse(
    code = 200,
    message = "Login successful",
    response = User.class,
    responseHeaders = {
        @ResponseHeader(
            name = "Authorization",
            description = "JWT token for subsequent requests",
            response = String.class
        ),
        @ResponseHeader(
            name = "X-Token-Expires",
            description = "Token expiration timestamp",
            response = Long.class
        )
    }
)
@POST
@Path("/login")
public Response login(LoginRequest request) {
    // implementation
}

// File download with metadata headers
@ApiResponse(
    code = 200,
    message = "File downloaded successfully",
    responseHeaders = {
        @ResponseHeader(
            name = "Content-Type",
            description = "MIME type of the file",
            response = String.class
        ),
        @ResponseHeader(
            name = "Content-Length", 
            description = "Size of file in bytes",
            response = Long.class
        ),
        @ResponseHeader(
            name = "Content-Disposition",
            description = "Attachment filename",
            response = String.class
        ),
        @ResponseHeader(
            name = "Last-Modified",
            description = "File modification timestamp", 
            response = String.class
        )
    }
)
@GET
@Path("/files/{id}/download")
public Response downloadFile(@PathParam("id") String fileId) {
    // implementation
}

// Pagination headers
@ApiResponse(
    code = 200,
    message = "Page retrieved successfully",
    response = User.class,
    responseContainer = "List",
    responseHeaders = {
        @ResponseHeader(
            name = "X-Total-Count",
            description = "Total number of items available",
            response = Integer.class
        ),
        @ResponseHeader(
            name = "X-Page-Count",
            description = "Total number of pages",
            response = Integer.class
        ),
        @ResponseHeader(
            name = "Link",
            description = "Links to first, last, next, and previous pages",
            response = String.class
        )
    }
)
@GET
public Response getUsers(
    @QueryParam("page") @DefaultValue("1") Integer page,
    @QueryParam("size") @DefaultValue("20") Integer size
) {
    // implementation
}

Common Response Patterns

REST CRUD Operations

@Path("/users")
public class UserController {

    // GET collection
    @ApiResponses({
        @ApiResponse(
            code = 200,
            message = "Users retrieved successfully",
            response = User.class,
            responseContainer = "List",
            responseHeaders = @ResponseHeader(name = "X-Total-Count", response = Integer.class)
        ),
        @ApiResponse(code = 204, message = "No users found")
    })
    @GET
    public Response getAllUsers() {
        // implementation
    }

    // GET single resource
    @ApiResponses({
        @ApiResponse(code = 200, message = "User found", response = User.class),
        @ApiResponse(code = 404, message = "User not found", response = ErrorResponse.class)
    })
    @GET
    @Path("/{id}")
    public Response getUser(@PathParam("id") Long id) {
        // implementation
    }

    // POST create
    @ApiResponses({
        @ApiResponse(
            code = 201,
            message = "User created successfully",
            response = User.class,
            responseHeaders = @ResponseHeader(name = "Location", response = String.class)
        ),
        @ApiResponse(code = 400, message = "Invalid user data", response = ErrorResponse.class),
        @ApiResponse(code = 409, message = "User already exists", response = ErrorResponse.class)
    })
    @POST
    public Response createUser(User user) {
        // implementation
    }

    // PUT update
    @ApiResponses({
        @ApiResponse(code = 200, message = "User updated successfully", response = User.class),
        @ApiResponse(code = 404, message = "User not found", response = ErrorResponse.class),
        @ApiResponse(code = 400, message = "Invalid user data", response = ErrorResponse.class)
    })
    @PUT
    @Path("/{id}")
    public Response updateUser(@PathParam("id") Long id, User user) {
        // implementation
    }

    // DELETE
    @ApiResponses({
        @ApiResponse(code = 204, message = "User deleted successfully"),
        @ApiResponse(code = 404, message = "User not found", response = ErrorResponse.class),
        @ApiResponse(code = 409, message = "Cannot delete user with active dependencies", response = ErrorResponse.class)
    })
    @DELETE
    @Path("/{id}")
    public Response deleteUser(@PathParam("id") Long id) {
        // implementation
    }
}

Error Response Models

@ApiModel(description = "Standard error response")
public class ErrorResponse {
    
    @ApiModelProperty(value = "Error code", required = true, example = "VALIDATION_ERROR")
    private String code;
    
    @ApiModelProperty(value = "Human-readable error message", required = true, example = "Invalid input data")
    private String message;
    
    @ApiModelProperty(value = "Request timestamp", example = "2023-01-15T10:30:00Z")
    private LocalDateTime timestamp;
    
    @ApiModelProperty(value = "Request path", example = "/api/users")
    private String path;
    
    @ApiModelProperty(value = "Validation errors")
    private List<FieldError> fieldErrors;
}

@ApiModel(description = "Field validation error")
public class FieldError {
    
    @ApiModelProperty(value = "Field name", example = "email")
    private String field;
    
    @ApiModelProperty(value = "Rejected value", example = "invalid-email")
    private Object rejectedValue;
    
    @ApiModelProperty(value = "Error message", example = "Must be a valid email address")
    private String message;
}

Async and Long-Running Operations

// Async operation initiation
@ApiResponses({
    @ApiResponse(
        code = 202,
        message = "Processing started",
        response = JobResponse.class,
        responseHeaders = @ResponseHeader(name = "Location", description = "Job status URL", response = String.class)
    ),
    @ApiResponse(code = 400, message = "Invalid request", response = ErrorResponse.class)
})
@POST
@Path("/bulk-import")
public Response startBulkImport(BulkImportRequest request) {
    // implementation
}

// Job status checking
@ApiResponses({
    @ApiResponse(code = 200, message = "Job status retrieved", response = JobStatus.class),
    @ApiResponse(code = 404, message = "Job not found", response = ErrorResponse.class)
})
@GET
@Path("/jobs/{jobId}")
public Response getJobStatus(@PathParam("jobId") String jobId) {
    // implementation
}

@ApiModel(description = "Background job response")
public class JobResponse {
    
    @ApiModelProperty(value = "Job identifier", example = "job-12345")
    private String jobId;
    
    @ApiModelProperty(value = "Job status URL", example = "/api/jobs/job-12345")
    private String statusUrl;
    
    @ApiModelProperty(value = "Estimated completion time", example = "2023-01-15T11:00:00Z")
    private LocalDateTime estimatedCompletion;
}

File Operations

// File upload
@ApiResponses({
    @ApiResponse(
        code = 201,
        message = "File uploaded successfully",
        response = FileInfo.class,
        responseHeaders = {
            @ResponseHeader(name = "Location", description = "File URL", response = String.class),
            @ResponseHeader(name = "ETag", description = "File hash", response = String.class)
        }
    ),
    @ApiResponse(code = 400, message = "Invalid file", response = ErrorResponse.class),
    @ApiResponse(code = 413, message = "File too large", response = ErrorResponse.class),
    @ApiResponse(code = 415, message = "Unsupported file type", response = ErrorResponse.class)
})
@POST
@Path("/upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(
    @FormDataParam("file") InputStream fileInputStream,
    @FormDataParam("file") FormDataContentDisposition fileDetail
) {
    // implementation
}

// File download
@ApiResponses({
    @ApiResponse(
        code = 200,
        message = "File content",
        responseHeaders = {
            @ResponseHeader(name = "Content-Type", response = String.class),
            @ResponseHeader(name = "Content-Length", response = Long.class),
            @ResponseHeader(name = "Content-Disposition", response = String.class)
        }
    ),
    @ApiResponse(code = 404, message = "File not found", response = ErrorResponse.class),
    @ApiResponse(code = 403, message = "Access denied", response = ErrorResponse.class)
})
@GET
@Path("/files/{id}")
public Response downloadFile(@PathParam("id") String fileId) {
    // implementation
}

Best Practices

  1. Document all possible responses - Include success, client error, and server error scenarios
  2. Use appropriate HTTP status codes - Follow HTTP specification and REST conventions
  3. Provide meaningful messages - Clear, human-readable descriptions of each response
  4. Include error response models - Document the structure of error responses
  5. Document response headers - Include important headers like Location, ETag, etc.
  6. Use container types - Specify "List", "Set", or "Map" for collection responses
  7. Document async patterns - Include 202 responses for long-running operations
  8. Consider edge cases - Document rate limiting, validation errors, conflicts, etc.
  9. Be consistent - Use consistent response patterns across your API
  10. Include examples - Provide sample response bodies in your models

Install with Tessl CLI

npx tessl i tessl/maven-io-swagger--swagger-annotations

docs

core-api.md

documentation.md

extensions.md

index.md

models.md

parameters.md

responses.md

security.md

tile.json