Newer
Older

Jeremy M Fee
committed
import os
from typing import Dict, Union
from fastapi import FastAPI, Request, Response
from fastapi.exceptions import RequestValidationError
from fastapi.middleware.cors import CORSMiddleware

Jeremy M Fee
committed
from fastapi.responses import JSONResponse, PlainTextResponse, RedirectResponse
from obspy import UTCDateTime
from . import algorithms, data, elements, metadata, observatories
ERROR_CODE_MESSAGES = {
204: "No Data",
400: "Bad Request",
404: "Not Found",
409: "Conflict",
500: "Internal Server Error",
501: "Not Implemented",
503: "Service Unavailable",
}
METADATA_ENDPOINT = os.getenv("METADATA_ENDPOINT", False)

Jeremy M Fee
committed
VERSION = os.getenv("GEOMAG_VERSION", "version")

Jeremy M Fee
committed
app = FastAPI(docs_url="/docs", root_path="/ws")
app.include_router(algorithms.router)
app.include_router(data.router)
app.include_router(elements.router)
app.include_router(observatories.router)
if METADATA_ENDPOINT == True:

Rivers, Travis (Contractor) Creighton
committed
app.include_router(metadata.router)
async def add_headers(request: Request, call_next):
response = await call_next(request)
response.headers[
"Access-Control-Allow-Headers"
] = "accept, origin, authorization, content-type"
response.headers["Access-Control-Allow-Methods"] = "*"
response.headers["Access-Control-Allow-Origin"] = "*"
response.headers["Cache-Control"] = "max-age=60"
@app.get("/", include_in_schema=False)
async def redirect_to_docs():
return RedirectResponse("/ws/docs")

Jeremy M Fee
committed
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
"""Value errors are user errors."""

Jeremy M Fee
committed
data_format = (
"format" in request.query_params
and str(request.query_params["format"])
or "text"
)
return format_error(400, str(exc), data_format, request)
@app.exception_handler(Exception)

Jeremy M Fee
committed
async def server_exception_handler(request: Request, exc: Exception):
"""Other exceptions are server errors."""

Jeremy M Fee
committed
data_format = (
"format" in request.query_params
and str(request.query_params["format"])
or "text"
)
return format_error(500, str(exc), data_format, request)
def format_error(
status_code: int, exception: str, format: str, request: Request
) -> Response:
"""Assign error_body value based on error format."""
if format == "json":
return json_error(status_code, exception, request.url)
else:

Jeremy M Fee
committed
return text_error(status_code, exception, request.url)

Jeremy M Fee
committed
def json_error(code: int, error: Exception, url: str) -> Response:
"""Format json error message.
Returns
-------
error_body : str
body of json error message.
"""

Jeremy M Fee
committed
return JSONResponse(
content={
"type": "Error",
"metadata": {
"title": ERROR_CODE_MESSAGES[code],
"status": code,
"error": str(error),
"generated": f"{UTCDateTime().isoformat()}Z",
"url": str(url),
"version": VERSION,
},

Jeremy M Fee
committed
status_code=code,
)

Jeremy M Fee
committed
def text_error(code: int, error: Exception, url: str) -> Response:
"""Format error message as plain text
Returns
-------
error message formatted as plain text.
"""

Jeremy M Fee
committed
return PlainTextResponse(
content=f"""Error {code}: {ERROR_CODE_MESSAGES[code]}
{error}
Usage details are available from
Request:
{url}
Request Submitted:

Jeremy M Fee
committed
{UTCDateTime().isoformat()}Z

Jeremy M Fee
committed
""",
status_code=code,
)