Include non-FastAPI routes in api/docs

This commit is contained in:
mvdbeek
2022-03-19 16:56:46 +01:00
parent 9a34fba455
commit e5eed5cbe0
5 changed files with 38 additions and 23 deletions
+1
View File
@@ -705,6 +705,7 @@ class UniverseApplication(StructuredApp, GalaxyManagerApplication):
self.server_starttime = int(time.time()) # used for cachebusting
# Limit lifetime of tool shed repository cache to app startup
self.tool_shed_repository_cache = None
self.api_spec = None
log.info(f"Galaxy app startup finished {startup_timer}")
def _shutdown_queue_worker(self):
+18 -14
View File
@@ -5,6 +5,7 @@ import inspect
import logging
import os
import random
import re
import socket
import string
import time
@@ -106,27 +107,28 @@ class WebApplication(base.WebApplication):
Traverse all route paths starting with "api" and create an APISpec instance.
"""
# API specification builder
apispec = APISpec(title=self.name,
version="0.0.0-unsupported", # galaxy_app.config.version_major,
openapi_version="3.0.2")
import re, sys
from apispec import yaml_utils
RE_URL = re.compile(r"""
apispec = APISpec(
title=self.name, version="0.0.0-unsupported", openapi_version="3.0.2" # galaxy_app.config.version_major,
)
RE_URL = re.compile(
r"""
(?::\(|{)
(\w*)
(?::.*)?
(?:\)|})""", re.X)
(?:\)|})""",
re.X,
)
for rule in self.mapper.matchlist:
if rule.routepath.endswith(".:(format)") or not rule.routepath.startswith("api/"):
continue
# Try to replace routes various ways to encode variables with simple swagger {form}
swagger_path = "/%s" % RE_URL.sub(r'{\1}', rule.routepath)
controller = rule.defaults.get('controller', '')
action = rule.defaults.get('action', '')
swagger_path = "/%s" % RE_URL.sub(r"{\1}", rule.routepath)
controller = rule.defaults.get("controller", "")
action = rule.defaults.get("action", "")
# Get the list of methods for the route
methods = []
if rule.conditions:
m = rule.conditions.get('method', [])
m = rule.conditions.get("method", [])
methods = type(m) is str and [m] or m
# Find the controller class
if controller not in self.api_controllers:
@@ -137,12 +139,14 @@ class WebApplication(base.WebApplication):
log.warning("No action found for '%s' in class '%s' while building API spec", action, controller_class)
continue
action_method = getattr(controller_class, action)
# First try to load method docs from docstring
operations = yaml_utils.load_operations_from_docstring(action_method.__doc__)
operations = {}
# Add methods that have routes but are not documents
for method in methods:
if method.lower() not in operations:
operations[method.lower()] = {}
operations[method.lower()] = {
"description": f"This route has not yet been ported to FastAPI. The documentation may not be complete.\n{action_method.__doc__}",
"tags": ["routes"],
}
# Store the swagger path
apispec.path(path=swagger_path, operations=operations)
return apispec
-9
View File
@@ -1,9 +0,0 @@
from galaxy import web
from galaxy.webapps.base.controller import BaseAPIController
class GenomesController(BaseAPIController):
@web.expose_api_raw
def index(self, trans, **kwd):
return trans.webapp.build_apispec().to_yaml()
+1
View File
@@ -260,6 +260,7 @@ def app_pair(global_conf, load_app_kwds=None, wsgi_preflight=True, **kwargs):
# ==== Done
# Indicate that all configuration settings have been provided
webapp.finalize_config()
app.api_spec = webapp.build_apispec()
# Wrap the webapp in some useful middleware
if kwargs.get("middleware", True):
+18
View File
@@ -6,12 +6,14 @@ from fastapi import (
FastAPI,
Request,
)
from fastapi.openapi.utils import get_openapi
from starlette.middleware.cors import CORSMiddleware
from starlette.responses import (
FileResponse,
Response,
)
from galaxy.version import VERSION
from galaxy.webapps.base.api import (
add_exception_handler,
add_request_id_middleware,
@@ -121,6 +123,21 @@ def add_galaxy_middleware(app: FastAPI, gx_app):
return response
def include_legacy_openapi(app, gx_app):
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title="Galaxy API Documentation",
version=VERSION,
routes=app.routes,
)
legacy_openapi = gx_app.api_spec.to_dict()
legacy_openapi["paths"].update(openapi_schema["paths"])
openapi_schema["paths"] = legacy_openapi["paths"]
app.openapi_schema = openapi_schema
return app.openapi_schema
def initialize_fast_app(gx_wsgi_webapp, gx_app):
app = FastAPI(
title="Galaxy API",
@@ -131,6 +148,7 @@ def initialize_fast_app(gx_wsgi_webapp, gx_app):
add_galaxy_middleware(app, gx_app)
add_request_id_middleware(app)
include_all_package_routers(app, "galaxy.webapps.galaxy.api")
include_legacy_openapi(app, gx_app)
wsgi_handler = WSGIMiddleware(gx_wsgi_webapp)
app.mount("/", wsgi_handler)
if gx_app.config.galaxy_url_prefix != "/":