1
0
mirror of https://github.com/checktheroads/hyperglass synced 2024-05-11 05:55:08 +00:00

improve api docs

This commit is contained in:
checktheroads
2020-01-21 02:38:04 -07:00
parent 52c2489658
commit 94c35faac0
3 changed files with 68 additions and 27 deletions

View File

@@ -5,9 +5,11 @@ import tempfile
from pathlib import Path
# Third Party Imports
from fastapi import BackgroundTasks
from fastapi import FastAPI
from fastapi import HTTPException
from fastapi.openapi.docs import get_redoc_html
from fastapi.openapi.docs import get_swagger_ui_html
from fastapi.openapi.utils import get_openapi
from prometheus_client import CONTENT_TYPE_LATEST
from prometheus_client import CollectorRegistry
from prometheus_client import Counter
@@ -33,6 +35,7 @@ from hyperglass.exceptions import ResponseEmpty
from hyperglass.exceptions import RestError
from hyperglass.exceptions import ScrapeError
from hyperglass.models.query import Query
from hyperglass.models.response import QueryResponse
from hyperglass.query import REDIS_CONFIG
from hyperglass.query import handle_query
from hyperglass.util import check_python
@@ -50,32 +53,24 @@ STATIC_FILES = "\n".join([str(STATIC_DIR), str(UI_DIR), str(IMAGES_DIR), str(NEX
log.debug(f"Static Files: {STATIC_FILES}")
docs_mode_map = {"swagger": "docs_url", "redoc": "redoc_url"}
docs_config = {"docs_url": None, "redoc_url": None}
if params.general.docs.enable:
if params.general.docs.mode == "swagger":
docs_config["docs_url"] = params.general.docs.uri
docs_config["redoc_url"] = None
elif params.general.docs.mode == "redoc":
docs_config["docs_url"] = None
docs_config["redoc_url"] = params.general.docs.uri
# Main App Definition
app = FastAPI(
debug=params.general.debug,
title=params.general.site_title,
description=params.general.site_description,
version=__version__,
**docs_config,
default_response_class=UJSONResponse,
docs_url=None,
redoc_url=None,
)
app.mount("/ui", StaticFiles(directory=UI_DIR), name="ui")
app.mount("/_next", StaticFiles(directory=NEXT_DIR), name="_next")
app.mount("/images", StaticFiles(directory=IMAGES_DIR), name="images")
app.mount("/ui/images", StaticFiles(directory=IMAGES_DIR), name="ui/images")
if params.general.docs.enable:
log.debug(f"API Docs config: {app.openapi()}")
DEV_URL = f"http://localhost:{str(params.general.listen_port)}/api/"
PROD_URL = "/api/"
@@ -91,6 +86,21 @@ app.add_middleware(
allow_headers=["*"],
)
def custom_openapi():
"""Generate custom OpenAPI config."""
openapi_schema = get_openapi(
title=params.general.site_title,
version=__version__,
description=params.general.site_description,
routes=app.routes,
)
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi
ASGI_PARAMS = {
"host": str(params.general.listen_address),
"port": params.general.listen_port,
@@ -199,7 +209,7 @@ tempdir = tempfile.TemporaryDirectory(prefix="hyperglass_")
os.environ["prometheus_multiproc_dir"] = tempdir.name
@app.get("/metrics")
@app.get("/metrics", include_in_schema=False)
async def metrics(request):
"""Serve Prometheus metrics."""
registry = CollectorRegistry()
@@ -214,7 +224,7 @@ async def metrics(request):
)
@app.get("/api/config")
@app.get("/api/config", include_in_schema=False)
async def frontend_config():
"""Provide validated user/default config for front end consumption.
@@ -224,16 +234,15 @@ async def frontend_config():
return UJSONResponse(frontend_params, status_code=200)
@app.post("/api/query/")
async def hyperglass_main(
query_data: Query, request: Request, background_tasks: BackgroundTasks
):
"""Process XHR POST data.
Ingests XHR POST data from
form submit, passes it to the backend application to perform the
filtering/lookups.
"""
@app.post(
"/api/query/",
summary=params.general.docs.endpoint_summary,
description=params.general.docs.endpoint_description,
response_model=QueryResponse,
tags=[params.general.docs.group_title],
)
async def query(query_data: Query, request: Request):
"""Ingest request data pass it to the backend application to perform the query."""
# Get client IP address for Prometheus logging & rate limiting
client_addr = request.client.host
@@ -259,6 +268,17 @@ async def hyperglass_main(
return UJSONResponse({"output": response}, status_code=200)
@app.get("/api/docs", include_in_schema=False)
async def docs():
"""Serve custom docs."""
if params.general.docs.enable:
docs_func_map = {"swagger": get_swagger_ui_html, "redoc": get_redoc_html}
docs_func = docs_func_map[params.general.docs.mode]
return docs_func(openapi_url=app.openapi_url, title=app.title + " - API Docs")
else:
raise HTTPException(detail="Not found", status_code=404)
def start():
"""Start the web server with Uvicorn ASGI."""
import uvicorn

View File

@@ -1,5 +1,7 @@
"""Configuration for API docs feature."""
# Third Party Imports
from pydantic import StrictBool
from pydantic import StrictStr
from pydantic import constr
# Project Imports
@@ -13,3 +15,6 @@ class Docs(HyperglassModel):
enable: StrictBool = True
mode: constr(regex=r"(swagger|redoc)") = "swagger"
uri: AnyUri = "/docs"
endpoint_summary: StrictStr = "Query Endpoint"
endpoint_description: StrictStr = "Request a query response per-location."
group_title: StrictStr = "Queries"

View File

@@ -0,0 +1,16 @@
"""Response model."""
# Standard Library Imports
from typing import List
# Third Party Imports
from pydantic import BaseModel
from pydantic import StrictStr
from pydantic import constr
class QueryResponse(BaseModel):
"""Query response model."""
output: StrictStr
alert: constr(regex=r"(warning|error|danger)")
keywords: List[StrictStr]