Skip to content
Snippets Groups Projects
Commit d150a9ee authored by Daniel Göbel's avatar Daniel Göbel
Browse files

Merge branch 'bugfix/68-manually-add-swagger-ui-to-activate-it' into 'development'

Resolve "Manually add Swagger UI to activate it"

Closes #68

See merge request !65
parents a2184f48 2aaf4de5
No related branches found
No related tags found
2 merge requests!71Delete dev branch,!65Resolve "Manually add Swagger UI to activate it"
Pipeline #39732 passed
......@@ -16,7 +16,6 @@ variables:
DB_USER: "random"
DB_DATABASE: "random"
DB_HOST: "random"
OTLP_GRPC_ENDPOINT: ""
cache:
paths:
......
......@@ -43,7 +43,6 @@ user-friendly manner. 👍
| Variable | Default | Value | Description |
|-----------------------------|----------------------|-----------------------------|----------------------------------------------------------------|
| `API_PREFIX` | `/api` | URL path | Prefix before every URL path |
| `BACKEND_CORS_ORIGINS` | `[]` | json formatted list of urls | List of valid CORS origins |
| `SQLALCHEMY_VERBOSE_LOGGER` | `false` | `<"true"&#x7c;"false">` | Enables verbose SQL output.<br>Should be `false` in production |
| `OPA_POLICY_PATH` | `/clowm/authz/allow` | URL path | Path to the OPA Policy for Authorization |
| `OTLP_GRPC_ENDPOINT` | unset | <hostname / IP> | OTLP compatible endpoint to send traces via gRPC, e.g. Jaeger |
from pathlib import Path
from typing import Any, Dict, List, Optional
from typing import Any, Dict, Optional
from pydantic import AnyHttpUrl, AnyUrl, Field, computed_field
from pydantic_settings import BaseSettings, SettingsConfigDict
......@@ -48,9 +48,6 @@ class Settings(BaseSettings):
def PUBLIC_KEY(self) -> str:
return _load_public_key(self.public_key_value, self.public_key_file)
# BACKEND_CORS_ORIGINS is a JSON-formatted list of origins
BACKEND_CORS_ORIGINS: List[AnyHttpUrl] = Field([], description="List of all valid CORS origins")
DB_HOST: str = Field(..., description="Host of the database.")
DB_USER: str = Field(..., description="Username in the database.")
DB_PASSWORD: str = Field(..., description="Password for the database user.")
......
......@@ -4,7 +4,8 @@ from fastapi import FastAPI, Request, Response, status
from fastapi.exception_handlers import http_exception_handler, request_validation_exception_handler
from fastapi.exceptions import RequestValidationError, StarletteHTTPException
from fastapi.middleware.gzip import GZipMiddleware
from fastapi.responses import JSONResponse
from fastapi.openapi.docs import get_swagger_ui_html
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.routing import APIRoute
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
......@@ -69,15 +70,6 @@ FastAPIInstrumentor.instrument_app(
app, excluded_urls="health,docs,openapi.json", tracer_provider=trace.get_tracer_provider()
)
# CORS Settings for the API (disabled)
# app.add_middleware(
# CORSMiddleware,
# allow_origins=settings.BACKEND_CORS_ORIGINS,
# allow_credentials=False,
# allow_methods=["*"],
# allow_headers=["*"],
# )
# Enable gzip compression for large responses
app.add_middleware(GZipMiddleware, minimum_size=500)
......@@ -85,15 +77,23 @@ app.add_middleware(GZipMiddleware, minimum_size=500)
app.include_router(api_router)
app.include_router(miscellaneous_router)
# Create Custom route for OpenAPI schema
# Hash openapi.json content and save it
m = md5()
m.update(JSONResponse(app.openapi()).body) # ensure the serialization is the same as the one in the route
openapi_hash = m.hexdigest()
del m
# manually add Swagger UI route
async def swagger_ui_html(req: Request) -> HTMLResponse:
return get_swagger_ui_html(
openapi_url=app.root_path + "/openapi.json",
title=app.title + " - Swagger UI",
swagger_favicon_url="/favicon.ico",
)
# Route for openapi.json file with ETag header for client cache support
app.add_route("/docs", swagger_ui_html, include_in_schema=False)
# Hash openapi.json content and ensure the serialization is the same as the one in the route
openapi_hash = md5(JSONResponse(app.openapi()).body).hexdigest()
# Create Custom route for OpenAPI schema
async def openapi(req: Request) -> Response:
# If schema on clients side is still valid, return empty Body with 304 response code (client will use cached body)
if req.headers.get("If-None-Match") == openapi_hash:
......
......@@ -24,7 +24,7 @@ class TestOpenAPIRoute:
@pytest.mark.asyncio
async def test_openapi_route(self, client: AsyncClient) -> None:
"""
Test getting the OpenAPI specification and the caching mechanism.
Test for getting the OpenAPI specification and the caching mechanism.
Parameters
----------
......@@ -37,3 +37,16 @@ class TestOpenAPIRoute:
response2 = await client.get("/openapi.json", headers={"If-None-Match": response1.headers.get("ETag")})
assert response2.status_code == status.HTTP_304_NOT_MODIFIED
@pytest.mark.asyncio
async def test_swagger_ui_route(self, client: AsyncClient) -> None:
"""
Test for getting the Swagger UI.
Parameters
----------
client : httpx.AsyncClient
HTTP Client to perform the request on.
"""
response1 = await client.get("/docs")
assert response1.status_code == status.HTTP_200_OK
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment