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

Document query parameters directly instead of via freeform text blurbs #804

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
d0714e0
Add `TODO` comment about importing `Annotated` from different packages
eecavanna Nov 30, 2024
60c048e
Bump FastAPI version to get support for Pydantic query param models
eecavanna Nov 30, 2024
1c31aaf
Add `TODO` comment about documenting existing function `get_mongo_sort`
eecavanna Dec 1, 2024
dcf5f28
Add `TODO` comment about hiding `/search` path from Swagger UI
eecavanna Dec 1, 2024
1507e79
Document "find"-related request parameters in a Swagger UI-visible way
eecavanna Dec 1, 2024
36981f5
style: reformat
invalid-email-address Dec 1, 2024
26113e9
Add description about `study_id` path parameter
eecavanna Dec 1, 2024
0e00f79
style: reformat
invalid-email-address Dec 1, 2024
4bf0fe5
Add description about `sample_id` path parameter
eecavanna Dec 1, 2024
993124e
Add description about `/data_objects/study/{study_id}` path parameter
eecavanna Dec 1, 2024
a4ac300
Customize endpoint description to contain only user-relevant information
eecavanna Dec 1, 2024
ae02df0
style: reformat
invalid-email-address Dec 1, 2024
aab577c
Add description about `/data_objects/{data_object_id}` path parameter
eecavanna Dec 1, 2024
cb03a8a
Add `TODO` note about documenting existing class `PipelineFindRequest`
eecavanna Dec 1, 2024
b89cc81
style: reformat
invalid-email-address Dec 1, 2024
84e260c
Add lots of `TODO` comments about documenting undocumented functions
eecavanna Dec 1, 2024
27b58fb
Prepare to document or remove "pipeline search" endpoints
eecavanna Dec 2, 2024
a123f51
Remove now-redundant parameter documentation above "find" endpoint group
eecavanna Dec 2, 2024
afdfd4b
Refine documentation of changesheet-related endpoints
eecavanna Dec 3, 2024
2f63a00
style: reformat
invalid-email-address Dec 3, 2024
e286746
Add `TODO`s about documenting GridFS-related endpoint
eecavanna Dec 3, 2024
3cc5c4c
Add `TODO`s about documenting helper functions
eecavanna Dec 3, 2024
d2e3879
Replace copy/pasted function definition with reference to existing one
eecavanna Dec 3, 2024
1be5c00
Document `collection_name` path parameter and refactor validation code
eecavanna Dec 3, 2024
8fea5e3
Document "list"-related request parameters in a Swagger UI-visible way
eecavanna Dec 3, 2024
644775b
Make `TODO` comment be more specific
eecavanna Dec 3, 2024
65b46e7
style: reformat
invalid-email-address Dec 3, 2024
d1fbaae
Adopt example values from freeform blurb
eecavanna Dec 3, 2024
3f72db4
Document `doc_id` path parameter and standalone `projection` query param
eecavanna Dec 3, 2024
fe4a61e
Remove now-redundant parameter documentation from atop "metadata" group
eecavanna Dec 3, 2024
c0975eb
style: reformat
invalid-email-address Dec 3, 2024
97cd7f6
Merge branch 'main' into 665B-convert-swagger-tag-metadata-freeform-b…
eecavanna Dec 4, 2024
9c12669
style: reformat
invalid-email-address Dec 4, 2024
442d6d4
fix: remove unfinished, unused pipeline_search endpoints and supporti…
dwinston Dec 5, 2024
e00c4bb
docs: clarify and diminish visibility of `/metadata/stored_files/{obj…
dwinston Dec 5, 2024
0738f37
docs: add https://w3id.org/nmdc/ links
dwinston Dec 5, 2024
52ff29c
docs: docstring etc. for `documentation_links` helper
dwinston Dec 5, 2024
26e0a2f
docs: do not include `GET /search` in api docs
dwinston Dec 5, 2024
bec364a
rm: remove unimplemented cruft
dwinston Dec 5, 2024
ba6d235
docs: docstring for `raw_changesheet_from_uploaded_file`
dwinston Dec 5, 2024
4234e84
rm: nuke `POST /metadata/json:validate_urls_file` and helper fns
dwinston Dec 5, 2024
f7cf00c
feat: unify projection-qarg parsing and simplify implementation
dwinston Dec 5, 2024
c168ca3
doc: docstring for `check_filter`
dwinston Dec 5, 2024
e6bcb1b
doc: rename fn to be less ambiguous
dwinston Dec 5, 2024
e499507
doc: docstring for `get_mongo_filter`
dwinston Dec 5, 2024
a557faf
doc: docstring for `get_mongo_sort` helper fn
dwinston Dec 5, 2024
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
112 changes: 55 additions & 57 deletions nmdc_runtime/api/endpoints/find.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from operator import itemgetter
from typing import List, Annotated

from fastapi import APIRouter, Depends, Form, Path
from fastapi import APIRouter, Depends, Form, Path, Query
from jinja2 import Environment, PackageLoader, select_autoescape
from nmdc_runtime.minter.config import typecodes
from nmdc_runtime.util import get_nmdc_jsonschema_dict
Expand All @@ -21,15 +21,12 @@
find_resources,
strip_oid,
find_resources_spanning,
pipeline_find_resources,
)
from nmdc_runtime.api.models.metadata import Doc
from nmdc_runtime.api.models.util import (
FindResponse,
FindRequest,
entity_attributes_to_index,
PipelineFindRequest,
PipelineFindResponse,
)
from nmdc_runtime.util import get_class_names_from_collection_spec

Expand All @@ -42,7 +39,7 @@
response_model_exclude_unset=True,
)
def find_studies(
req: FindRequest = Depends(),
req: Annotated[FindRequest, Query()],
mdb: MongoDatabase = Depends(get_mongo_db),
):
"""
Expand All @@ -58,7 +55,14 @@ def find_studies(
response_model_exclude_unset=True,
)
def find_study_by_id(
study_id: str,
study_id: Annotated[
str,
Path(
title="Study ID",
description="The `id` of the `Study` you want to find.\n\n_Example_: `nmdc:sty-11-abc123`",
examples=["nmdc:sty-11-abc123"],
),
],
mdb: MongoDatabase = Depends(get_mongo_db),
):
"""
Expand All @@ -74,7 +78,7 @@ def find_study_by_id(
response_model_exclude_unset=True,
)
def find_biosamples(
req: FindRequest = Depends(),
req: Annotated[FindRequest, Query()],
mdb: MongoDatabase = Depends(get_mongo_db),
):
"""
Expand All @@ -90,7 +94,14 @@ def find_biosamples(
response_model_exclude_unset=True,
)
def find_biosample_by_id(
sample_id: str,
sample_id: Annotated[
str,
Path(
title="Biosample ID",
description="The `id` of the `Biosample` you want to find.\n\n_Example_: `nmdc:bsm-11-abc123`",
examples=["nmdc:bsm-11-abc123"],
),
],
mdb: MongoDatabase = Depends(get_mongo_db),
):
"""
Expand All @@ -106,7 +117,7 @@ def find_biosample_by_id(
response_model_exclude_unset=True,
)
def find_data_objects(
req: FindRequest = Depends(),
req: Annotated[FindRequest, Query()],
mdb: MongoDatabase = Depends(get_mongo_db),
):
"""
Expand Down Expand Up @@ -135,9 +146,22 @@ def get_classname_from_typecode(doc_id: str) -> str:
@router.get(
"/data_objects/study/{study_id}",
response_model_exclude_unset=True,
# Note: We include a description here so that FastAPI does not use the function's docstring as the API endpoint's
# description. The docstring currently contains non-user-facing information, such as mentioning the
# implementation detail of using the `alldocs` collection under the hood, and mentioning function parameters
# that are not API request parameters.
description="Gets all `DataObject`s related to all `Biosample`s related to the specified `Study`.",
)
def find_data_objects_for_study(
study_id: str,
study_id: Annotated[
str,
Path(
title="Study ID",
description="""The `id` of the `Study` having `Biosample`s with which you want to find
associated `DataObject`s.\n\n_Example_: `nmdc:sty-11-abc123`""",
examples=["nmdc:sty-11-abc123"],
),
],
mdb: MongoDatabase = Depends(get_mongo_db),
):
"""This API endpoint is used to retrieve data objects associated with
Expand Down Expand Up @@ -256,7 +280,14 @@ def process_informed_by_docs(doc, collected_objects, unique_ids):
response_model_exclude_unset=True,
)
def find_data_object_by_id(
data_object_id: str,
data_object_id: Annotated[
str,
Path(
title="DataObject ID",
description="The `id` of the `DataObject` you want to find.\n\n_Example_: `nmdc:dobj-11-abc123`",
examples=["nmdc:dobj-11-abc123"],
),
],
mdb: MongoDatabase = Depends(get_mongo_db),
):
"""
Expand All @@ -274,19 +305,17 @@ def find_data_object_by_id(
response_model_exclude_unset=True,
)
def find_planned_processes(
req: FindRequest = Depends(),
req: Annotated[FindRequest, Query()],
mdb: MongoDatabase = Depends(get_mongo_db),
):
# TODO: Add w3id URL links for classes (e.g. <https://w3id.org/nmdc/PlannedProcess>) when they resolve
# to Berkeley schema definitions.
"""
The GET /planned_processes endpoint is a general way to fetch metadata about various planned processes (e.g.
workflow execution, material processing, etc.). Any "slot" (a.k.a. attribute) for
`PlannedProcess` may be used in the filter
[`PlannedProcess`](https://w3id.org/nmdc/PlannedProcess) may be used in the filter
and sort parameters, including attributes of subclasses of *PlannedProcess*.

For example, attributes used in subclasses such as `Extraction` (subclass of *PlannedProcess*),
can be used as input criteria for the filter and sort parameters of this endpoint.
For example, attributes used in subclasses such as [`Extraction`](https://w3id.org/nmdc/Extraction)
(subclass of *PlannedProcess*), can be used as input criteria for the filter and sort parameters of this endpoint.
"""
return find_resources_spanning(
req,
Expand Down Expand Up @@ -346,13 +375,17 @@ def attr_index_sort_key(attr):


def documentation_links(jsonschema_dict, collection_names) -> dict:
"""TODO: Add a docstring saying what this function does at a high level."""
"""This function constructs a hierarchical catalog of (links to) schema classes and their slots.

# TODO: Document the purpose of this initial key.
doc_links = {"Activity": []}
The returned dictionary `doc_links` is used as input to the Jinja template `nmdc_runtime/templates/search.html`
in order to support user experience for `GET /search`.
"""

# Note: All documentation URLs generated within this function will begin with this.
base_url = r"https://microbiomedata.github.io/nmdc-schema"
base_url = r"https://w3id.org/nmdc"

# Initialize dictionary in which to associate key/value pairs via the following for loop.
doc_links = {}

for collection_name in collection_names:
# Since a given collection can be associated with multiple classes, the `doc_links` dictionary
Expand Down Expand Up @@ -398,7 +431,7 @@ def documentation_links(jsonschema_dict, collection_names) -> dict:
return doc_links


@router.get("/search", response_class=HTMLResponse)
@router.get("/search", response_class=HTMLResponse, include_in_schema=False)
def search_page(
mdb: MongoDatabase = Depends(get_mongo_db),
):
Expand All @@ -423,38 +456,3 @@ def search_page(
doc_links=doc_links,
)
return HTMLResponse(content=html_content, status_code=200)


@router.post(
"/pipeline_search",
response_model=PipelineFindResponse,
response_model_exclude_unset=True,
)
def pipeline_search(
req: PipelineFindRequest = Depends(),
mdb: MongoDatabase = Depends(get_mongo_db),
):
return pipeline_find_resources(req, mdb)


@router.post(
"/pipeline_search_form",
response_model=PipelineFindResponse,
response_model_exclude_unset=True,
)
def pipeline_search(
pipeline_spec: str = Form(...),
description: str = Form(...),
mdb: MongoDatabase = Depends(get_mongo_db),
):
req = PipelineFindRequest(pipeline_spec=pipeline_spec, description=description)
return pipeline_find_resources(req, mdb)


@router.get("/pipeline_search", response_class=HTMLResponse)
def pipeline_search(
mdb: MongoDatabase = Depends(get_mongo_db),
):
template = jinja_env.get_template("pipeline_search.html")
html_content = template.render()
return HTMLResponse(content=html_content, status_code=200)
25 changes: 3 additions & 22 deletions nmdc_runtime/api/endpoints/jobs.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import json
from typing import Optional
from typing import Optional, Annotated

import pymongo
from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, Query

from nmdc_runtime.api.core.util import (
raise404_if_none,
Expand All @@ -25,7 +25,7 @@
"/jobs", response_model=ListResponse[Job], response_model_exclude_unset=True
)
def list_jobs(
req: ListRequest = Depends(),
req: Annotated[ListRequest, Query()],
mdb: pymongo.database.Database = Depends(get_mongo_db),
maybe_site: Optional[Site] = Depends(maybe_get_current_client_site),
):
Expand Down Expand Up @@ -55,22 +55,3 @@ def claim_job(
site: Site = Depends(get_current_client_site),
):
return _claim_job(job_id, mdb, site)


@router.get(
"/jobs/{job_id}/executions",
description=(
"A sub-resource of a job resource, the result of a successful run of that job. "
"An execution resource may be retrieved by any site; however, it may be created "
"and updated only by the site that ran its job."
),
)
def list_job_executions():
# TODO
pass


@router.get("/jobs/{job_id}/executions/{exec_id}")
def get_job_execution():
# TODO
pass
Loading
Loading