Skip to content

Commit

Permalink
Add routing to automatically generate openAPI metadata for the biothi…
Browse files Browse the repository at this point in the history
…ngs annotator service (#43)

* Add the metadata routes to the application

* Add most of the structure to the openAPI spec

* Get the general metadata structure setup

* Add the openapi headers for the version view

* Finalize the metadata autodoc generation

* Simplify the metadata tests

* Fix formatting issues with yaml docstrings

* Update the routing for the openapi metadata

---------

Co-authored-by: jschaff <[email protected]>
  • Loading branch information
ctrl-schaff and jschaff authored Oct 1, 2024
1 parent f52446b commit 094bcc6
Show file tree
Hide file tree
Showing 5 changed files with 532 additions and 52 deletions.
99 changes: 99 additions & 0 deletions biothings_annotator/application/metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
"""
Applicaton metadata manipulation and configuration methods
"""

import sanic
from sanic_ext.extensions.openapi.definitions import Contact, Info, Tag
from sanic_ext.extensions.openapi.types import Definition
from sanic_ext.utils.route import remove_nulls


def apply_openapi_metadata(application: sanic.Sanic):
"""
Method for applying our metadata from the application.
We're wishing to avoid a static metadata file so we'll
have to do some overriding of the specification builder
with the parameters we wish in python rather than statically
via a JSON or YAML file. If that changes in the future,
please replace this code with a hard-coded file.
"""

# Description
specification_builder = application.ext.openapi

# Info override
specification_builder._build_info = _build_info

# Tags
annotation_tags = {
"gene_tag": "gene",
"chemical_tag": "chemical",
"drug_tag": "drug",
"disease_tag": "disease",
"phenotype_tag": "phenotype",
"annotation_tag": "annotation",
"translator_tag": "translator",
}
for tag_key, tag_name in annotation_tags.items():
specification_builder.tags[tag_key] = Tag(name=tag_name)

# Servers
production_server = {
"url": "https://biothings.ncats.io/annotator",
"description": "Production Server",
"x-maturity": "production",
}
staging_server = {
"url": "https://biothings.test.transltr.io/annotator",
"description": "Staging Server",
}
integration_server = {
"url": "http://biothings.ci.transltr.io/annotator",
"description": "CI Server",
}
server_instances = [
AnnotationServer(**production_server),
AnnotationServer(**staging_server),
AnnotationServer(**integration_server),
]
application.ext.openapi._servers = server_instances


class AnnotationServer(Definition):
url: str
description: str


def _build_info() -> Info:
"""
Overridden method for info building.
At the moment it forces the `Info` object
that's created to not support specification
extension fields so we have to supplant the current
method with this one at runtime before building
This method is called by the `SpecificationBuilder`
instance in the `build` method
"""
# Contact
contact_mapping = {
"email": "[email protected]",
"name": "BioThings Team",
"x-id": "https://github.com/biothings",
"x-role": "responsible developers",
}
openapi_contact = Contact(**contact_mapping)

x_translator = {"component": "Utility", "team": ["Service Provider"]}
info_mapping = {
"contact": openapi_contact,
"description": "Translator Annotation Service",
"termsOfService": "https://biothings.io/about",
"title": "Translator Annotation Service",
"version": "1.0",
"x-translator": x_translator,
}
info_mapping = remove_nulls(info_mapping, deep=False)
openapi_info = Info(**info_mapping)
return openapi_info
28 changes: 19 additions & 9 deletions biothings_annotator/application/views/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
from typing import Dict, List

from .annotator import StatusView, VersionView, BatchCurieView, CurieView, TrapiView, CurieLegacyView, TrapiLegacyView
from biothings_annotator.application.views.annotator import (
BatchCurieView,
CurieLegacyView,
CurieView,
StatusView,
TrapiLegacyView,
TrapiView,
)
from biothings_annotator.application.views.metadata import MetadataView, VersionView


def build_routes() -> List[Dict]:
Expand All @@ -22,13 +29,6 @@ def build_routes() -> List[Dict]:
"name": "status_endpoint",
}

# --- VERSION ROUTE ---
version_route_main = {
"handler": VersionView.as_view(),
"uri": r"/version",
"name": "version_endpoint",
}

# --- CURIE ROUTES ---
curie_route_main = {
"handler": CurieView.as_view(),
Expand All @@ -52,6 +52,15 @@ def build_routes() -> List[Dict]:
trapi_route_main = {"handler": TrapiView.as_view(), "uri": "/trapi/", "name": "trapi_endpoint"}
trapi_route_mirror = {"handler": TrapiLegacyView.as_view(), "uri": "/annotator/", "name": "trapi_endpoint_mirror"}

# --- METADATA ROUTES ---
metadata_route = {"handler": MetadataView.as_view(), "uri": "/metadata/openapi", "name": "metadata"}

version_route_main = {
"handler": VersionView.as_view(),
"uri": r"/version",
"name": "version_endpoint",
}

route_collection = [
status_route_main,
version_route_main,
Expand All @@ -60,5 +69,6 @@ def build_routes() -> List[Dict]:
batch_curie_route,
trapi_route_main,
trapi_route_mirror,
metadata_route,
]
return route_collection
Loading

0 comments on commit 094bcc6

Please sign in to comment.