docs: add OpenAPI responses={} to all router endpoints
Add explicit HTTP status code documentation to every endpoint across 15 router files. Each endpoint now declares all possible response codes (200/201/204/400/401/404/409/429/502/503) with descriptions so frontend can distinguish error types. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -213,6 +213,11 @@ _NamePath = Annotated[str, Path(description='Jail name as configured in fail2ban
|
||||
"",
|
||||
response_model=JailConfigListResponse,
|
||||
summary="List configuration for all active jails",
|
||||
responses={
|
||||
200: {"description": "Jail configs returned", "model": JailConfigListResponse},
|
||||
401: {"description": "Session missing, expired, or invalid"},
|
||||
502: {"description": "fail2ban unreachable"},
|
||||
},
|
||||
)
|
||||
async def get_jail_configs(
|
||||
request: Request,
|
||||
@@ -241,6 +246,11 @@ async def get_jail_configs(
|
||||
"/inactive",
|
||||
response_model=InactiveJailListResponse,
|
||||
summary="List all inactive jails discovered in config files",
|
||||
responses={
|
||||
200: {"description": "Inactive jail list returned", "model": InactiveJailListResponse},
|
||||
401: {"description": "Session missing, expired, or invalid"},
|
||||
502: {"description": "fail2ban unreachable"},
|
||||
},
|
||||
)
|
||||
async def get_inactive_jails(
|
||||
request: Request,
|
||||
@@ -268,6 +278,10 @@ async def get_inactive_jails(
|
||||
"/pending-recovery",
|
||||
response_model=PendingRecovery | None,
|
||||
summary="Return active crash-recovery record if one exists",
|
||||
responses={
|
||||
200: {"description": "Recovery record or null", "model": PendingRecovery},
|
||||
401: {"description": "Session missing, expired, or invalid"},
|
||||
},
|
||||
)
|
||||
async def get_pending_recovery(
|
||||
_auth: AuthDep,
|
||||
@@ -293,6 +307,12 @@ async def get_pending_recovery(
|
||||
"/{name}",
|
||||
response_model=JailConfigResponse,
|
||||
summary="Return configuration for a single jail",
|
||||
responses={
|
||||
200: {"description": "Jail config returned", "model": JailConfigResponse},
|
||||
401: {"description": "Session missing, expired, or invalid"},
|
||||
404: {"description": "Jail not found"},
|
||||
502: {"description": "fail2ban unreachable"},
|
||||
},
|
||||
)
|
||||
async def get_jail_config(
|
||||
request: Request,
|
||||
@@ -325,6 +345,15 @@ async def get_jail_config(
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
summary="Update jail configuration",
|
||||
dependencies=[Depends(_check_jail_update_rate_limit)],
|
||||
responses={
|
||||
204: {"description": "Jail config updated successfully"},
|
||||
400: {"description": "Set command rejected or invalid regex"},
|
||||
401: {"description": "Session missing, expired, or invalid"},
|
||||
404: {"description": "Jail not found"},
|
||||
422: {"description": "Regex pattern failed to compile"},
|
||||
429: {"description": "Rate limit exceeded for jail update operations"},
|
||||
502: {"description": "fail2ban unreachable"},
|
||||
},
|
||||
)
|
||||
async def update_jail_config(
|
||||
request: Request,
|
||||
@@ -365,6 +394,14 @@ async def update_jail_config(
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
summary="Add a log file path to an existing jail",
|
||||
dependencies=[Depends(_check_jail_create_rate_limit)],
|
||||
responses={
|
||||
204: {"description": "Log path added successfully"},
|
||||
400: {"description": "Command rejected or path invalid"},
|
||||
401: {"description": "Session missing, expired, or invalid"},
|
||||
404: {"description": "Jail not found"},
|
||||
429: {"description": "Rate limit exceeded for jail create operations"},
|
||||
502: {"description": "fail2ban unreachable"},
|
||||
},
|
||||
)
|
||||
async def add_log_path(
|
||||
request: Request,
|
||||
@@ -400,6 +437,15 @@ async def add_log_path(
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
summary="Remove a monitored log path from a jail",
|
||||
dependencies=[Depends(_check_jail_delete_rate_limit)],
|
||||
responses={
|
||||
204: {"description": "Log path removed successfully"},
|
||||
400: {"description": "Command rejected"},
|
||||
401: {"description": "Session missing, expired, or invalid"},
|
||||
404: {"description": "Jail not found"},
|
||||
422: {"description": "Log path outside allowed directories"},
|
||||
429: {"description": "Rate limit exceeded for jail delete operations"},
|
||||
502: {"description": "fail2ban unreachable"},
|
||||
},
|
||||
)
|
||||
async def delete_log_path(
|
||||
request: Request,
|
||||
@@ -440,6 +486,15 @@ async def delete_log_path(
|
||||
response_model=JailActivationResponse,
|
||||
summary="Activate an inactive jail",
|
||||
dependencies=[Depends(_check_jail_activate_rate_limit)],
|
||||
responses={
|
||||
200: {"description": "Jail activated", "model": JailActivationResponse},
|
||||
400: {"description": "Invalid jail name"},
|
||||
401: {"description": "Session missing, expired, or invalid"},
|
||||
404: {"description": "Jail not found in config files"},
|
||||
409: {"description": "Jail already active"},
|
||||
429: {"description": "Rate limit exceeded for jail activate operations"},
|
||||
502: {"description": "fail2ban unreachable"},
|
||||
},
|
||||
)
|
||||
async def activate_jail(
|
||||
app: AppDep,
|
||||
@@ -494,6 +549,15 @@ async def activate_jail(
|
||||
response_model=JailActivationResponse,
|
||||
summary="Deactivate an active jail",
|
||||
dependencies=[Depends(_check_jail_deactivate_rate_limit)],
|
||||
responses={
|
||||
200: {"description": "Jail deactivated", "model": JailActivationResponse},
|
||||
400: {"description": "Invalid jail name"},
|
||||
401: {"description": "Session missing, expired, or invalid"},
|
||||
404: {"description": "Jail not found in config files"},
|
||||
409: {"description": "Jail already inactive"},
|
||||
429: {"description": "Rate limit exceeded for jail deactivate operations"},
|
||||
502: {"description": "fail2ban unreachable"},
|
||||
},
|
||||
)
|
||||
async def deactivate_jail(
|
||||
_auth: AuthDep,
|
||||
@@ -536,6 +600,15 @@ async def deactivate_jail(
|
||||
"/{name}/local",
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
summary="Delete the jail.d override file for an inactive jail",
|
||||
responses={
|
||||
204: {"description": "Override file deleted successfully"},
|
||||
400: {"description": "Invalid jail name"},
|
||||
401: {"description": "Session missing, expired, or invalid"},
|
||||
404: {"description": "Jail not found in config files"},
|
||||
409: {"description": "Jail currently active"},
|
||||
500: {"description": "File cannot be deleted"},
|
||||
502: {"description": "fail2ban unreachable"},
|
||||
},
|
||||
)
|
||||
async def delete_jail_local_override(
|
||||
request: Request,
|
||||
@@ -578,6 +651,12 @@ async def delete_jail_local_override(
|
||||
"/{name}/validate",
|
||||
response_model=JailValidationResult,
|
||||
summary="Validate jail configuration before activation",
|
||||
responses={
|
||||
200: {"description": "Validation result", "model": JailValidationResult},
|
||||
400: {"description": "Invalid jail name"},
|
||||
401: {"description": "Session missing, expired, or invalid"},
|
||||
404: {"description": "Jail not found in config files"},
|
||||
},
|
||||
)
|
||||
async def validate_jail(
|
||||
request: Request,
|
||||
@@ -609,6 +688,12 @@ async def validate_jail(
|
||||
"/{name}/rollback",
|
||||
response_model=RollbackResponse,
|
||||
summary="Disable a bad jail config and restart fail2ban",
|
||||
responses={
|
||||
200: {"description": "Rollback completed", "model": RollbackResponse},
|
||||
400: {"description": "Invalid jail name"},
|
||||
401: {"description": "Session missing, expired, or invalid"},
|
||||
500: {"description": "Failed to write .local override file"},
|
||||
},
|
||||
)
|
||||
async def rollback_jail(
|
||||
_auth: AuthDep,
|
||||
@@ -654,6 +739,14 @@ async def rollback_jail(
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
summary="Assign a filter to a jail",
|
||||
dependencies=[Depends(_check_jail_create_rate_limit)],
|
||||
responses={
|
||||
204: {"description": "Filter assigned successfully"},
|
||||
400: {"description": "Invalid jail name or filter name"},
|
||||
401: {"description": "Session missing, expired, or invalid"},
|
||||
404: {"description": "Jail or filter not found"},
|
||||
429: {"description": "Rate limit exceeded for jail create operations"},
|
||||
500: {"description": "Failed to write .local override file"},
|
||||
},
|
||||
)
|
||||
async def assign_filter_to_jail(
|
||||
request: Request,
|
||||
@@ -689,6 +782,14 @@ async def assign_filter_to_jail(
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
summary="Add an action to a jail",
|
||||
dependencies=[Depends(_check_jail_create_rate_limit)],
|
||||
responses={
|
||||
204: {"description": "Action added successfully"},
|
||||
400: {"description": "Invalid jail name or action name"},
|
||||
401: {"description": "Session missing, expired, or invalid"},
|
||||
404: {"description": "Jail or action not found"},
|
||||
429: {"description": "Rate limit exceeded for jail create operations"},
|
||||
500: {"description": "Failed to write .local override file"},
|
||||
},
|
||||
)
|
||||
async def assign_action_to_jail(
|
||||
request: Request,
|
||||
@@ -725,6 +826,14 @@ async def assign_action_to_jail(
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
summary="Remove an action from a jail",
|
||||
dependencies=[Depends(_check_jail_delete_rate_limit)],
|
||||
responses={
|
||||
204: {"description": "Action removed successfully"},
|
||||
400: {"description": "Invalid jail name or action name"},
|
||||
401: {"description": "Session missing, expired, or invalid"},
|
||||
404: {"description": "Jail not found in config files"},
|
||||
429: {"description": "Rate limit exceeded for jail delete operations"},
|
||||
500: {"description": "Failed to write .local override file"},
|
||||
},
|
||||
)
|
||||
async def remove_action_from_jail(
|
||||
request: Request,
|
||||
|
||||
Reference in New Issue
Block a user