Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve accept header API schema #18668

Merged
merged 2 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions client/src/api/schema/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18035,6 +18035,8 @@ export interface operations {
order?: string | null;
};
header?: {
/** @description Accept header to determine the response format. Default is 'application/json'. */
accept?: "application/json" | "application/vnd.galaxy.history.contents.stats+json";
/** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */
"run-as"?: string | null;
};
Expand Down Expand Up @@ -19094,6 +19096,8 @@ export interface operations {
order?: string | null;
};
header?: {
/** @description Accept header to determine the response format. Default is 'application/json'. */
accept?: "application/json" | "application/vnd.galaxy.history.contents.stats+json";
/** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */
"run-as"?: string | null;
};
Expand All @@ -19105,12 +19109,11 @@ export interface operations {
};
};
responses: {
/** @description Successful Response */
/** @description The contents of the history that match the query. */
200: {
content: {
"application/json":
| components["schemas"]["HistoryContentsResult"]
| components["schemas"]["HistoryContentsWithStatsResult"];
"application/json": components["schemas"]["HistoryContentsResult"];
"application/vnd.galaxy.history.contents.stats+json": components["schemas"]["HistoryContentsWithStatsResult"];
};
};
/** @description Request Error */
Expand Down Expand Up @@ -19686,6 +19689,8 @@ export interface operations {
offset?: number | null;
};
header?: {
/** @description Accept header to determine the response format. Default is 'application/json'. */
accept?: "application/json" | "application/vnd.galaxy.task.export+json";
/** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */
"run-as"?: string | null;
};
Expand Down
12 changes: 12 additions & 0 deletions lib/galaxy/schema/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,15 @@ def ModelClassField(default_value):
description="The name of the database model class.",
json_schema_extra={"const": literal_to_value(default_value), "type": "string"},
)


def accept_wildcard_defaults_to_json(v):
assert isinstance(v, str)
# Accept header can have multiple comma separated values.
# If any of these values is the wildcard - we default to application/json.
if "*/*" in v:
return "application/json"
return v


AcceptHeaderValidator = BeforeValidator(accept_wildcard_defaults_to_json)
18 changes: 16 additions & 2 deletions lib/galaxy/webapps/galaxy/api/histories.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from typing import (
Any,
List,
Literal,
Optional,
Union,
)
Expand All @@ -33,7 +34,10 @@
FilterQueryParams,
SerializationParams,
)
from galaxy.schema.fields import DecodedDatabaseIdField
from galaxy.schema.fields import (
AcceptHeaderValidator,
DecodedDatabaseIdField,
)
from galaxy.schema.history import (
HistoryIndexQueryPayload,
HistorySortByEnum,
Expand Down Expand Up @@ -163,6 +167,16 @@ class CreateHistoryFormData(CreateHistoryPayload):
"""Uses Form data instead of JSON"""


IndexExportsAcceptHeader = Annotated[
Literal[
"application/json",
"application/vnd.galaxy.task.export+json",
],
AcceptHeaderValidator,
Header(description="Accept header to determine the response format. Default is 'application/json'."),
]


@router.cbv
class FastAPIHistories:
service: HistoriesService = depends(HistoriesService)
Expand Down Expand Up @@ -516,7 +530,7 @@ def index_exports(
trans: ProvidesHistoryContext = DependsOnTrans,
limit: Optional[int] = LimitQueryParam,
offset: Optional[int] = OffsetQueryParam,
accept: str = Header(default="application/json", include_in_schema=False),
accept: IndexExportsAcceptHeader = "application/json",
) -> Union[JobExportHistoryArchiveListResponse, ExportTaskListResponse]:
"""
By default the legacy job-based history exports (jeha) are returned.
Expand Down
56 changes: 36 additions & 20 deletions lib/galaxy/webapps/galaxy/api/history_contents.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import logging
from typing import (
List,
Literal,
Optional,
Union,
)
Expand All @@ -22,6 +23,7 @@
Response,
StreamingResponse,
)
from typing_extensions import Annotated

from galaxy import util
from galaxy.managers.context import ProvidesHistoryContext
Expand All @@ -30,7 +32,10 @@
SerializationParams,
ValueFilterQueryParams,
)
from galaxy.schema.fields import DecodedDatabaseIdField
from galaxy.schema.fields import (
AcceptHeaderValidator,
DecodedDatabaseIdField,
)
from galaxy.schema.schema import (
AnyHistoryContentItem,
AnyJobStateSummary,
Expand Down Expand Up @@ -374,13 +379,40 @@ def parse_index_jobs_summary_params(
return HistoryContentsIndexJobsSummaryParams(ids=util.listify(ids), types=util.listify(types))


HistoryIndexAcceptContentTypes = Annotated[
Literal[
"application/json",
"application/vnd.galaxy.history.contents.stats+json",
],
AcceptHeaderValidator,
Header(description="Accept header to determine the response format. Default is 'application/json'."),
]

HistoryIndexResponsesSchema = {
200: {
"description": ("The contents of the history that match the query."),
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/HistoryContentsResult"}, # HistoryContentsResult.schema(),
},
HistoryContentsWithStatsResult.__accept_type__: {
"schema": { # HistoryContentsWithStatsResult.schema(),
"$ref": "#/components/schemas/HistoryContentsWithStatsResult"
},
},
},
},
}


@router.cbv
class FastAPIHistoryContents:
service: HistoriesContentsService = depends(HistoriesContentsService)

@router.get(
"/api/histories/{history_id}/contents/{type}s",
summary="Returns the contents of the given history filtered by type.",
responses=HistoryIndexResponsesSchema,
operation_id="history_contents__index_typed",
response_model_exclude_unset=True,
)
Expand All @@ -393,7 +425,7 @@ def index_typed(
legacy_params: LegacyHistoryContentsIndexParams = Depends(get_legacy_index_query_params),
serialization_params: SerializationParams = Depends(query_serialization_params),
filter_query_params: FilterQueryParams = Depends(get_filter_query_params),
accept: str = Header(default="application/json", include_in_schema=False),
accept: HistoryIndexAcceptContentTypes = "application/json",
) -> Union[HistoryContentsResult, HistoryContentsWithStatsResult]:
"""
Return a list of either `HDA`/`HDCA` data for the history with the given ``ID``.
Expand All @@ -419,23 +451,7 @@ def index_typed(
"/api/histories/{history_id}/contents",
name="history_contents",
summary="Returns the contents of the given history.",
responses={
200: {
"description": ("The contents of the history that match the query."),
"content": {
"application/json": {
"schema": { # HistoryContentsResult.schema(),
"$ref": "#/components/schemas/HistoryContentsResult"
},
},
HistoryContentsWithStatsResult.__accept_type__: {
"schema": { # HistoryContentsWithStatsResult.schema(),
"$ref": "#/components/schemas/HistoryContentsWithStatsResult"
},
},
},
},
},
responses=HistoryIndexResponsesSchema,
operation_id="history_contents__index",
response_model_exclude_unset=True,
)
Expand All @@ -448,7 +464,7 @@ def index(
legacy_params: LegacyHistoryContentsIndexParams = Depends(get_legacy_index_query_params),
serialization_params: SerializationParams = Depends(query_serialization_params),
filter_query_params: FilterQueryParams = Depends(get_filter_query_params),
accept: str = Header(default="application/json", include_in_schema=False),
accept: HistoryIndexAcceptContentTypes = "application/json",
) -> Union[HistoryContentsResult, HistoryContentsWithStatsResult]:
"""
Return a list of `HDA`/`HDCA` data for the history with the given ``ID``.
Expand Down
Loading