From 26ae9a21dd01bd3393c6a996b4510250b83a00e5 Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Wed, 22 May 2024 10:21:47 -0400 Subject: [PATCH] feat: OpenAPI schema + interactive docs --- bento_reference_service/authz.py | 10 ++++++- bento_reference_service/config.py | 3 +++ bento_reference_service/constants.py | 10 +++---- bento_reference_service/main.py | 10 ++++++- poetry.lock | 39 ++++++++++++++-------------- pyproject.toml | 2 +- 6 files changed, 46 insertions(+), 28 deletions(-) diff --git a/bento_reference_service/authz.py b/bento_reference_service/authz.py index e13094d..2caf6dd 100644 --- a/bento_reference_service/authz.py +++ b/bento_reference_service/authz.py @@ -1,3 +1,4 @@ +import re from bento_lib.auth.middleware.fastapi import FastApiAuthMiddleware from .config import get_config from .logger import get_logger @@ -8,4 +9,11 @@ # Non-standard middleware setup so that we can import the instance and use it for dependencies too config = get_config() # TODO: Find a way to DI this -authz_middleware = FastApiAuthMiddleware.build_from_pydantic_config(config, get_logger(config)) +authz_middleware = FastApiAuthMiddleware.build_from_pydantic_config( + config, + get_logger(config), + exempt_request_patterns=( + (r"GET", re.escape(config.service_docs_path)), + (r"GET", re.escape(config.service_openapi_path)), + ), +) diff --git a/bento_reference_service/config.py b/bento_reference_service/config.py index 46433b2..fd0d3bc 100644 --- a/bento_reference_service/config.py +++ b/bento_reference_service/config.py @@ -19,6 +19,9 @@ class Config(BentoBaseConfig): service_description: str = "Reference data (genomes & annotations) service for the Bento platform." service_url_base_path: str = "http://127.0.0.1:5000" # Base path to construct URIs from + service_docs_path: str = "/docs" + service_openapi_path: str = "/openapi.json" + database_uri: str = "postgres://localhost:5432" file_ingest_tmp_dir: Path = Path(__file__).parent.parent / "tmp" # Default to repository `tmp` folder file_ingest_chunk_size: int = 1024 * 256 # 256 KiB at a time diff --git a/bento_reference_service/constants.py b/bento_reference_service/constants.py index db77e9c..b14884b 100644 --- a/bento_reference_service/constants.py +++ b/bento_reference_service/constants.py @@ -1,4 +1,6 @@ import re +from bento_lib.service_info.constants import SERVICE_GROUP_BENTO +from bento_lib.service_info.helpers import build_bento_service_type from bento_reference_service import __version__ __all__ = [ @@ -11,13 +13,9 @@ BENTO_SERVICE_KIND = "reference" -SERVICE_GROUP = "ca.c3g.bento" +SERVICE_GROUP = SERVICE_GROUP_BENTO SERVICE_ARTIFACT = BENTO_SERVICE_KIND -SERVICE_TYPE = { - "group": SERVICE_GROUP, - "artifact": SERVICE_ARTIFACT, - "version": __version__, -} +SERVICE_TYPE = build_bento_service_type(SERVICE_ARTIFACT, __version__) RANGE_HEADER_PATTERN = re.compile(r"^bytes=(\d+)-(\d+)?$") diff --git a/bento_reference_service/main.py b/bento_reference_service/main.py index c489ddc..614669d 100644 --- a/bento_reference_service/main.py +++ b/bento_reference_service/main.py @@ -2,6 +2,7 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.exceptions import RequestValidationError, StarletteHTTPException +from urllib.parse import urlparse from bento_lib.responses.fastapi_errors import ( http_exception_handler_factory, @@ -37,7 +38,14 @@ async def lifespan(_app: FastAPI): yield -app = FastAPI(lifespan=lifespan) +app = FastAPI( + title=config_for_setup.service_name, + root_path=urlparse(config_for_setup.service_url_base_path).path, + docs_url=config_for_setup.service_docs_path, + openapi_url=config_for_setup.service_openapi_path, + version=__version__, + lifespan=lifespan, +) # Attach different routers to the app, for: # - genome listing diff --git a/poetry.lock b/poetry.lock index 36cc979..186af1c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -137,13 +137,13 @@ frozenlist = ">=1.1.0" [[package]] name = "annotated-types" -version = "0.6.0" +version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" files = [ - {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, - {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, ] [[package]] @@ -257,13 +257,13 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p [[package]] name = "bento-lib" -version = "11.7.2" +version = "11.9.0" description = "A set of common utilities and helpers for Bento platform services." optional = false python-versions = "<4.0,>=3.10" files = [ - {file = "bento_lib-11.7.2-py3-none-any.whl", hash = "sha256:11c534d0866ba050970e05966081884b065f059af126063de1c1504566d9c50f"}, - {file = "bento_lib-11.7.2.tar.gz", hash = "sha256:cdaf7bb1dec1da1aec4565184d8b738723d424b72f968cf93877770ab4c17b49"}, + {file = "bento_lib-11.9.0-py3-none-any.whl", hash = "sha256:f89a3116ac3dd568e7d7595d41a7387d390adc68da989fc4325ee76e49459eae"}, + {file = "bento_lib-11.9.0.tar.gz", hash = "sha256:a985e9e2e5f4e61fd4d47e551c6c52e6fb7d3a5b2936c3f312025f0dade95f63"}, ] [package.dependencies] @@ -690,19 +690,20 @@ all = ["email_validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)" [[package]] name = "fastapi-cli" -version = "0.0.3" +version = "0.0.4" description = "Run and manage FastAPI apps from the command line with FastAPI CLI. 🚀" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi_cli-0.0.3-py3-none-any.whl", hash = "sha256:ae233115f729945479044917d949095e829d2d84f56f55ce1ca17627872825a5"}, - {file = "fastapi_cli-0.0.3.tar.gz", hash = "sha256:3b6e4d2c4daee940fb8db59ebbfd60a72c4b962bcf593e263e4cc69da4ea3d7f"}, + {file = "fastapi_cli-0.0.4-py3-none-any.whl", hash = "sha256:a2552f3a7ae64058cdbb530be6fa6dbfc975dc165e4fa66d224c3d396e25e809"}, + {file = "fastapi_cli-0.0.4.tar.gz", hash = "sha256:e2e9ffaffc1f7767f488d6da34b6f5a377751c996f397902eb6abb99a67bde32"}, ] [package.dependencies] -fastapi = "*" typer = ">=0.12.3" -uvicorn = {version = ">=0.15.0", extras = ["standard"]} + +[package.extras] +standard = ["fastapi", "uvicorn[standard] (>=0.15.0)"] [[package]] name = "filelock" @@ -1609,13 +1610,13 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "pytest-asyncio" -version = "0.23.6" +version = "0.23.7" description = "Pytest support for asyncio" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-asyncio-0.23.6.tar.gz", hash = "sha256:ffe523a89c1c222598c76856e76852b787504ddb72dd5d9b6617ffa8aa2cde5f"}, - {file = "pytest_asyncio-0.23.6-py3-none-any.whl", hash = "sha256:68516fdd1018ac57b846c9846b954f0393b26f094764a28c955eabb0536a4e8a"}, + {file = "pytest_asyncio-0.23.7-py3-none-any.whl", hash = "sha256:009b48127fbe44518a547bddd25611551b0e43ccdbf1e67d12479f569832c20b"}, + {file = "pytest_asyncio-0.23.7.tar.gz", hash = "sha256:5f5c72948f4c49e7db4f29f2521d4031f1c27f86e57b046126654083d4770268"}, ] [package.dependencies] @@ -1766,13 +1767,13 @@ rpds-py = ">=0.7.0" [[package]] name = "requests" -version = "2.31.0" +version = "2.32.2" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"}, + {file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"}, ] [package.dependencies] @@ -2501,4 +2502,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.10.0" -content-hash = "c46a7f9fb29a9e4e3eef8da4c9bbd210bef32ca2196a9e0c81d8822017f43c5b" +content-hash = "3eb8b9caf027548e84e246c4fce111df41115b0bc53a02605ee5d057ae6bcfec" diff --git a/pyproject.toml b/pyproject.toml index 06281f5..88c641c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,7 @@ classifiers = [ python = "^3.10.0" fastapi = "^0.111.0" pydantic = "^2.6.1" -bento-lib = {extras = ["fastapi"], version = "^11.7.2"} +bento-lib = {extras = ["fastapi"], version = "^11.9.0"} aiofiles = "^23.2.1" pysam = "~0.22.0" jsonschema = "^4.21.1"