Skip to content

Commit b3b9881

Browse files
authored
Merge pull request #244 from ecmwf-projects/COPDS-2395-improve-swagger-doc
Improve swagger documentation
2 parents a4b14e0 + d7fa8e6 commit b3b9881

File tree

8 files changed

+79
-28
lines changed

8 files changed

+79
-28
lines changed

cads_processing_api_service/auth.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def get_auth_header(pat: str | None = None, jwt: str | None = None) -> tuple[str
4040
Parameters
4141
----------
4242
pat : str | None, optional
43-
Personal Access Token
43+
API Token
4444
jwt : str | None, optional
4545
JSON Web Token
4646
@@ -125,19 +125,24 @@ def authenticate_user(
125125

126126
def get_auth_info(
127127
pat: str | None = fastapi.Header(
128-
None, description="Personal Access Token", alias="PRIVATE-TOKEN"
128+
None, description="API Token.", alias="PRIVATE-TOKEN"
129129
),
130130
jwt: str | None = fastapi.Header(
131-
None, description="JSON Web Token", alias="Authorization"
131+
None,
132+
description="JSON Web Token",
133+
alias="Authorization",
134+
include_in_schema=False,
135+
),
136+
portal_header: str | None = fastapi.Header(
137+
None, alias=SETTINGS.portal_header_name, include_in_schema=False
132138
),
133-
portal_header: str | None = fastapi.Header(None, alias=SETTINGS.portal_header_name),
134139
) -> models.AuthInfo | None:
135140
"""Get authentication information from the incoming HTTP request.
136141
137142
Parameters
138143
----------
139144
pat : str | None, optional
140-
Personal Access Token
145+
API Token
141146
jwt : str | None, optional
142147
JSON Web Token
143148
portal_header : str | None, optional

cads_processing_api_service/clients.py

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,12 @@ class DatabaseClient(ogc_api_processes_fastapi.clients.BaseClient):
8686
@exceptions.exception_logger
8787
def get_processes(
8888
self,
89-
limit: int | None = fastapi.Query(10, ge=1, le=10000),
89+
limit: int | None = fastapi.Query(
90+
10, ge=1, le=10000, description="Maximum number of results to return."
91+
),
9092
sortby: utils.ProcessSortCriterion | None = fastapi.Query(
91-
utils.ProcessSortCriterion.resource_uid_asc
93+
utils.ProcessSortCriterion.resource_uid_asc,
94+
description="Sorting criterion.",
9295
),
9396
cursor: str | None = fastapi.Query(None, include_in_schema=False),
9497
back: bool | None = fastapi.Query(None, include_in_schema=False),
@@ -148,7 +151,7 @@ def get_processes(
148151
def get_process(
149152
self,
150153
response: fastapi.Response,
151-
process_id: str = fastapi.Path(...),
154+
process_id: str = fastapi.Path(..., description="Process identifier."),
152155
portals: tuple[str] | None = fastapi.Depends(utils.get_portals),
153156
) -> ogc_api_processes_fastapi.models.ProcessDescription:
154157
"""Implement OGC API - Processes `GET /processes/{process_id}` endpoint.
@@ -201,7 +204,7 @@ def get_process(
201204
def post_process_execution(
202205
self,
203206
request: fastapi.Request,
204-
process_id: str = fastapi.Path(...),
207+
process_id: str = fastapi.Path(..., description="Process identifier."),
205208
execution_content: models.Execute = fastapi.Body(...),
206209
auth_info: models.AuthInfo = fastapi.Depends(auth.get_auth_info),
207210
) -> models.StatusInfo:
@@ -330,18 +333,30 @@ def post_process_execution(
330333
@exceptions.exception_logger
331334
def get_jobs(
332335
self,
333-
processID: list[str] | None = fastapi.Query(None),
336+
processID: list[str] | None = fastapi.Query(
337+
None,
338+
description=(
339+
"Processes identifiers. Only jobs associated to the specified "
340+
"processes shall be included in the response."
341+
),
342+
),
334343
status: list[models.StatusCode] | None = fastapi.Query(
335344
[
336345
ogc_api_processes_fastapi.models.StatusCode.accepted,
337346
ogc_api_processes_fastapi.models.StatusCode.running,
338347
ogc_api_processes_fastapi.models.StatusCode.successful,
339348
ogc_api_processes_fastapi.models.StatusCode.failed,
340-
]
349+
],
350+
description=(
351+
"Job statuses. Only jobs with the specified statuses shall be included in "
352+
"the response."
353+
),
354+
),
355+
limit: int | None = fastapi.Query(
356+
10, ge=1, le=10000, description="Maximum number of results to return."
341357
),
342-
limit: int | None = fastapi.Query(10, ge=1, le=10000),
343358
sortby: utils.JobSortCriterion | None = fastapi.Query(
344-
utils.JobSortCriterion.created_at_desc
359+
utils.JobSortCriterion.created_at_desc, description="Sorting criterion."
345360
),
346361
cursor: str | None = fastapi.Query(None, include_in_schema=False),
347362
back: bool | None = fastapi.Query(None, include_in_schema=False),
@@ -459,12 +474,21 @@ def get_jobs(
459474
@exceptions.exception_logger
460475
def get_job(
461476
self,
462-
job_id: str = fastapi.Path(...),
463-
qos: bool = fastapi.Query(False),
464-
request: bool = fastapi.Query(False),
465-
log: bool = fastapi.Query(False),
477+
job_id: str = fastapi.Path(..., description="Job identifier."),
478+
qos: bool = fastapi.Query(
479+
False, description="Whether to include job qos info in the response."
480+
),
481+
request: bool = fastapi.Query(
482+
False,
483+
description="Whether to include the sumbitted request in the response.",
484+
),
485+
log: bool = fastapi.Query(
486+
False, description="Whether to include the job's log in the response."
487+
),
466488
log_start_time: datetime.datetime | None = fastapi.Query(
467-
None, alias="logStartTime"
489+
None,
490+
alias="logStartTime",
491+
description="Datetime of the first log message to be returned.",
468492
),
469493
auth_info: models.AuthInfo = fastapi.Depends(auth.get_auth_info),
470494
) -> models.StatusInfo:
@@ -589,7 +613,7 @@ def get_job(
589613
@exceptions.exception_logger
590614
def get_job_results(
591615
self,
592-
job_id: str = fastapi.Path(...),
616+
job_id: str = fastapi.Path(..., description="Job identifier."),
593617
auth_info: models.AuthInfo = fastapi.Depends(auth.get_auth_info),
594618
) -> ogc_api_processes_fastapi.models.Results:
595619
"""Implement OGC API - Processes `GET /jobs/{job_id}/results` endpoint.
@@ -652,7 +676,7 @@ def get_job_results(
652676
@exceptions.exception_logger
653677
def delete_job(
654678
self,
655-
job_id: str = fastapi.Path(...),
679+
job_id: str = fastapi.Path(..., description="Job identifier."),
656680
auth_info: models.AuthInfo = fastapi.Depends(auth.get_auth_info),
657681
) -> ogc_api_processes_fastapi.models.StatusInfo:
658682
"""Implement OGC API - Processes `DELETE /jobs/{job_id}` endpoint.

cads_processing_api_service/config.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@
3131

3232
logger: structlog.stdlib.BoundLogger = structlog.get_logger(__name__)
3333

34+
API_TITLE = "CADS Processing API"
35+
API_DESCRIPTION = (
36+
"This REST API service enables the submission of processing tasks (data retrieval) to the "
37+
"CADS system, and their consequent monitoring and management. "
38+
"The service is based on the [OGC API - Processes standard](https://ogcapi.ogc.org/processes/).\n\n"
39+
"Being based on the OGC API - Processes standard, some terminology is inherited from it. "
40+
"In the context of this specific API, each _process_ is associated with a specific dataset "
41+
"and enables the retrieval of data from that dataset: as such, each _process_ identifier "
42+
"corresponds to a specific dataset identifier.\n"
43+
"A _job_, instead, is a specific data retrieval task that has been submitted for execution."
44+
)
45+
3446
API_REQUEST_TEMPLATE = """import cdsapi
3547
3648
dataset = "{process_id}"
@@ -189,6 +201,9 @@ def profiles_api_url(self) -> str:
189201
cache_resources_maxsize: int = 1000
190202
cache_resources_ttl: int = 10
191203

204+
api_title: str = API_TITLE
205+
api_description: str = API_DESCRIPTION
206+
192207
api_request_template: str = API_REQUEST_TEMPLATE
193208
api_request_max_list_length: dict[str, int] = API_REQUEST_MAX_LIST_LENGTH
194209
missing_dataset_title: str = "Dataset not available"

cads_processing_api_service/constraints.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
@exceptions.exception_logger
1313
def apply_constraints(
14-
process_id: str = fastapi.Path(...),
14+
process_id: str = fastapi.Path(..., description="Process identifier."),
1515
execution_content: models.Execute = fastapi.Body(...),
1616
portals: tuple[str] | None = fastapi.Depends(utils.get_portals),
1717
) -> dict[str, Any]:

cads_processing_api_service/costing.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ class RequestOrigin(str, enum.Enum):
3434

3535
@exceptions.exception_logger
3636
def estimate_cost(
37-
process_id: str = fastapi.Path(...),
38-
request_origin: RequestOrigin = fastapi.Query("api"),
39-
mandatory_inputs: bool = fastapi.Query(False),
37+
process_id: str = fastapi.Path(..., description="Process identifier."),
38+
request_origin: RequestOrigin = fastapi.Query("api", include_in_schema=False),
39+
mandatory_inputs: bool = fastapi.Query(False, include_in_schema=False),
4040
execution_content: models.Execute = fastapi.Body(...),
4141
portals: tuple[str] | None = fastapi.Depends(utils.get_portals),
4242
) -> models.RequestCost:

cads_processing_api_service/main.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,12 @@ async def lifespan(application: fastapi.FastAPI) -> AsyncGenerator[Any, None]:
6868

6969
logger = structlog.get_logger(__name__)
7070

71+
7172
app = ogc_api_processes_fastapi.instantiate_app(
7273
client=clients.DatabaseClient(), # type: ignore
7374
exception_handler=exceptions.exception_handler,
75+
title=SETTINGS.api_title,
76+
description=SETTINGS.api_description,
7477
)
7578
app = exceptions.include_exception_handlers(app)
7679
# FIXME : "app.router.lifespan_context" is not officially supported and would likely break
@@ -91,11 +94,13 @@ async def lifespan(application: fastapi.FastAPI) -> AsyncGenerator[Any, None]:
9194
app.router.add_api_route(
9295
"/processes/{process_id}/api-request",
9396
translators.get_api_request,
94-
description="Get API request equivalent to the submitted prrocess execution json.",
97+
description="Get API request equivalent to the submitted process execution json.",
9598
methods=["POST"],
9699
)
97100

98-
app.router.add_api_route("/metrics", starlette_exporter.handle_metrics)
101+
app.router.add_api_route(
102+
"/metrics", starlette_exporter.handle_metrics, include_in_schema=False
103+
)
99104
app.add_middleware(middlewares.ProcessingPrometheusMiddleware, group_paths=True)
100105

101106

cads_processing_api_service/translators.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ def format_api_request(
337337

338338
@exceptions.exception_logger
339339
def get_api_request(
340-
process_id: str = fastapi.Path(...),
340+
process_id: str = fastapi.Path(..., description="Process identifier."),
341341
request: dict[str, Any] = fastapi.Body(...),
342342
) -> dict[str, str]:
343343
"""Get CADS API request equivalent to the provided processing request.

cads_processing_api_service/utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,9 @@ def make_status_info(
662662

663663

664664
def get_portals(
665-
portal_header: str | None = fastapi.Header(None, alias=SETTINGS.portal_header_name),
665+
portal_header: str | None = fastapi.Header(
666+
None, alias=SETTINGS.portal_header_name, include_in_schema=False
667+
),
666668
) -> tuple[str, ...] | None:
667669
"""Get the list of portals from the incoming HTTP request's header.
668670

0 commit comments

Comments
 (0)