-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
107 lines (90 loc) · 3.29 KB
/
main.py
File metadata and controls
107 lines (90 loc) · 3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
"""
An API interface that provide two functionalities
(1) Accent Marker (/api/MarkAccent/)
(2) Furigana Marker (/api/MarkFurigana/)
(3) Usage Query (/api/UsageQuery/)
(4) Dictionary Query (/api/DictQuery/)
(5) Sentence Query (/api/SentenceQuery/)
"""
import logging
import secrets
from contextlib import asynccontextmanager
from typing import AsyncGenerator
import httpx
from fastapi import Depends, FastAPI, HTTPException, Security
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.security.api_key import APIKeyHeader
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.errors import RateLimitExceeded
from slowapi.middleware import SlowAPIMiddleware
from slowapi.util import get_remote_address
from starlette.status import HTTP_403_FORBIDDEN
from api import accent_marker, dict_query, furigana_marker, sentence_query, usage_query
from config.settings import ALLOW_ORIGINS, ALLOWED_HOSTS, X_API_KEY
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
"""
Lifespan context manager for FastAPI application.
This function is used to manage the lifespan of the FastAPI application.
It can be used to set up resources before the application starts and
clean up resources after the application stops.
Args:
app (FastAPI): The FastAPI application instance.
"""
# Set up resources before the application starts
app.state.http_client = httpx.AsyncClient(timeout=10.0)
yield
# Clean up resources after the application stops
await app.state.http_client.aclose()
app = FastAPI(lifespan=lifespan)
# Configure CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=ALLOW_ORIGINS,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Configure Trusted Host middleware
app.add_middleware(
TrustedHostMiddleware,
allowed_hosts=ALLOWED_HOSTS,
)
# TODO: adjust rate limit as needed for each api endpoint
limiter = Limiter(
key_func=get_remote_address,
default_limits=["60/minute"],
)
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) # type: ignore
app.add_middleware(SlowAPIMiddleware)
# API Key Header for API key authentication
api_key_header = APIKeyHeader(name="X-API-KEY", auto_error=False)
async def get_api_key(api_key: str = Security(api_key_header)) -> None:
if not secrets.compare_digest(api_key or "", X_API_KEY):
raise HTTPException(
status_code=HTTP_403_FORBIDDEN, detail="Could not validate credentials"
)
# Include routers from different modules
app.include_router(
accent_marker.router, prefix="/api", dependencies=[Depends(get_api_key)]
)
app.include_router(
furigana_marker.router, prefix="/api", dependencies=[Depends(get_api_key)]
)
app.include_router(
usage_query.router, prefix="/api", dependencies=[Depends(get_api_key)]
)
app.include_router(
dict_query.router, prefix="/api", dependencies=[Depends(get_api_key)]
)
app.include_router(
sentence_query.router, prefix="/api", dependencies=[Depends(get_api_key)]
)
logging.basicConfig(
level=logging.INFO,
format="{asctime} [{levelname:^8s}] {message} ({name}.{module}:{lineno})",
datefmt="%Y-%m-%d %H:%M:%S",
style="{",
)