Skip to content

Commit

Permalink
Refactor API config and OAI metadata handling
Browse files Browse the repository at this point in the history
Closes #154: Complete endpoint tags documentation or drop it alltogether
  • Loading branch information
bkis committed Mar 13, 2024
1 parent ba70178 commit 7d0c22e
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 127 deletions.
26 changes: 14 additions & 12 deletions Tekst-API/tekst/__init__.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
from importlib import metadata


data = metadata.metadata(__package__)
_package_metadata = metadata.metadata(__package__)

# whyyyyy
license_url = [
e for e in data.get_all("Project-URL", failobj="") if e.startswith("License")
][0].split(", ")[1]
_project_urls = _package_metadata.get_all("Project-URL", failobj="")
license_url = [e for e in _project_urls if e.startswith("License, ")][0].split(", ")[1]
documentation = [e for e in _project_urls if e.startswith("Documentation, ")][0].split(
", "
)[1]

pkg_meta = dict(
version=data["Version"],
description=data["Summary"],
long_description=data["Description"],
license=data["License"],
package_metadata = dict(
version=_package_metadata["Version"],
description=_package_metadata["Summary"],
license=_package_metadata["License"],
license_url=license_url,
website=data["Home-page"],
website=_package_metadata["Home-page"],
documentation=documentation,
)

__version__ = pkg_meta["version"]
__version__ = package_metadata["version"]

del metadata, data
del metadata, _package_metadata
5 changes: 3 additions & 2 deletions Tekst-API/tekst/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ async def startup_routine(app: FastAPI) -> None:
if not _cfg.dev_mode or _cfg.dev_use_db:
await db.init_odm()
if not _cfg.dev_mode or _cfg.dev_use_es:
await search.init_es_client(overwrite_existing_index=_cfg.dev_mode)
pass
# await search.init_es_client(overwrite_existing_index=_cfg.dev_mode)
# # TEMP DEV
# await search.init_es_client(
# overwrite_existing_index=False
# )

settings = await get_settings() if _cfg.dev_use_db else PlatformSettings()
customize_openapi(app=app, cfg=_cfg, settings=settings)
customize_openapi(app=app, settings=settings)

if not _cfg.email_smtp_server:
log.warning("No SMTP server configured") # pragma: no cover
Expand Down
13 changes: 4 additions & 9 deletions Tekst-API/tekst/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
)
from pydantic_settings import BaseSettings, SettingsConfigDict

from tekst import pkg_meta
from tekst import package_metadata
from tekst.models.common import CustomHttpUrl
from tekst.utils import validators as val
from tekst.utils.strings import safe_name
Expand Down Expand Up @@ -194,14 +194,9 @@ def generate_db_name(cls, v: str) -> str:
@computed_field
@property
def tekst_info(self) -> dict[str, str]:
return {
"name": "Tekst",
"version": pkg_meta["version"],
"description": pkg_meta["description"],
"website": pkg_meta["website"],
"license": pkg_meta["license"],
"license_url": pkg_meta["license_url"],
}
info_data = {"name": "Tekst"}
info_data.update(package_metadata)
return info_data

@computed_field
@property
Expand Down
102 changes: 0 additions & 102 deletions Tekst-API/tekst/openapi.py

This file was deleted.

77 changes: 77 additions & 0 deletions Tekst-API/tekst/openapi/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from typing import Any
from urllib.parse import urljoin

from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi

from tekst.config import TekstConfig, get_config
from tekst.models.settings import PlatformSettings
from tekst.openapi.tags_metadata import get_tags_metadata
from tekst.utils import pick_translation


_cfg: TekstConfig = get_config() # get (possibly cached) config data


def customize_openapi(app: FastAPI, settings: PlatformSettings):
def _custom_openapi():
if not app.openapi_schema:
app.openapi_schema = generate_schema(app, settings)
return app.openapi_schema

app.openapi = _custom_openapi


def generate_schema(app: FastAPI, settings: PlatformSettings):
schema = get_openapi(
title=settings.info_platform_name,
version=_cfg.tekst_info["version"],
description=pick_translation(settings.info_subtitle),
routes=app.routes,
servers=[{"url": urljoin(str(_cfg.server_url), str(_cfg.api_path))}],
terms_of_service=settings.info_terms,
tags=get_tags_metadata(documentation_url=_cfg.tekst_info["documentation"]),
contact={
"name": settings.info_contact_name,
"url": settings.info_contact_url,
"email": settings.info_contact_email,
},
license_info={
"name": _cfg.tekst_info["license"],
"url": _cfg.tekst_info["license_url"],
},
separate_input_output_schemas=False,
)
return process_openapi_schema(schema=schema)


def process_openapi_schema(schema: dict[str, Any]) -> dict[str, Any]:
# schema["components"]["schemas"]["Foo"] = PlatformSettings.schema()
return schema


async def generate_openapi_schema(
to_file: bool, output_file: str, indent: int, sort_keys: bool
) -> str: # pragma: no cover
"""
Atomic operation for creating and processing the OpenAPI schema from outside of
the app context. This is used in __main__.py
"""

import json

from asgi_lifespan import LifespanManager

from tekst.app import app

async with LifespanManager(app): # noqa: SIM117
schema = app.openapi()
json_dump_args = {
"skipkeys": True,
"indent": indent or None,
"sort_keys": sort_keys,
}
if to_file:
with open(output_file, "w") as f:
json.dump(schema, f, **json_dump_args)
return json.dumps(schema, **json_dump_args)
86 changes: 86 additions & 0 deletions Tekst-API/tekst/openapi/tags_metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
from typing import Any


def get_tags_metadata(documentation_url: str) -> list[dict[str, Any]]:
return [
{
"name": "texts",
"description": "Texts configured on this platform",
"externalDocs": {
"description": "View full documentation",
"url": documentation_url,
},
},
{
"name": "locations",
"description": "Text locations (the structural units of a text)",
"externalDocs": {
"description": "View full documentation",
"url": documentation_url,
},
},
{
"name": "resources",
"description": "Resources related to certain texts",
"externalDocs": {
"description": "View full documentation",
"url": documentation_url,
},
},
{
"name": "contents",
"description": "Contents of resources",
"externalDocs": {
"description": "View full documentation",
"url": documentation_url,
},
},
{
"name": "search",
"description": "Search operations and search index maintenance",
"externalDocs": {
"description": "View full documentation",
"url": documentation_url,
},
},
{
"name": "browse",
"description": "Endpoints for effectively browsing the plaform data",
"externalDocs": {
"description": "View full documentation",
"url": documentation_url,
},
},
{
"name": "platform",
"description": "Platform-specific data, infos and operations",
"externalDocs": {
"description": "View full documentation",
"url": documentation_url,
},
},
{
"name": "users",
"description": "Registered users and their accounts",
"externalDocs": {
"description": "View full documentation",
"url": documentation_url,
},
},
{
"name": "bookmarks",
"description": "The current user's bookmarks",
"externalDocs": {
"description": "View full documentation",
"url": documentation_url,
},
},
{
"name": "auth",
"description": "Rregistration, authentication and security",
"externalDocs": {
"description": "View full documentation",
"url": documentation_url,
},
},
]
4 changes: 2 additions & 2 deletions Tekst-API/tests/test_api_platform.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import pytest

from httpx import AsyncClient
from tekst import pkg_meta
from tekst import package_metadata


@pytest.mark.anyio
async def test_platform_data(test_client: AsyncClient, status_fail_msg):
resp = await test_client.get("/platform")
assert resp.status_code == 200, status_fail_msg(200, resp)
assert resp.json()["tekst"]["version"] == pkg_meta["version"]
assert resp.json()["tekst"]["version"] == package_metadata["version"]


@pytest.mark.anyio
Expand Down

0 comments on commit 7d0c22e

Please sign in to comment.