Skip to content

Commit 36c91d1

Browse files
committed
__main__ file added for entrypoint for the api
1 parent 067ab8b commit 36c91d1

File tree

12 files changed

+134
-80
lines changed

12 files changed

+134
-80
lines changed

Makefile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,12 @@ profile-builtin: ## Profile the file with cProfile and shows the report in the t
174174
docker-build: ## Build docker image
175175
docker build --tag ${DOCKER_IMAGE} --file docker/Dockerfile --target ${DOCKER_TARGET} .
176176

177-
run-local-app: ## Run the app in the local mode
178-
uv run --module fastapi run app/main.py --reload --port 8000
177+
run-dev: ## Run the app in the dev mode
178+
# uv run --module uvicorn app.main:app --port 8000
179+
uv run --module app.__main__
180+
181+
# run-prod: ## Run the app in the prod mode
182+
# uv run --module fastapi run app/main.py --port 8000
179183

180184
run-ui:
181185
uv run --module uvicorn ui.main:app --host 0.0.0.0 --port 5002

app/__main__.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import os
2+
import shutil
3+
from pathlib import Path
4+
5+
import uvicorn
6+
7+
from app.core.config import settings
8+
9+
10+
def set_multiproc_dir() -> None:
11+
"""
12+
Sets mutiproc_dir env variable.
13+
14+
This function cleans up the multiprocess directory
15+
and recreates it. This actions are required by prometheus-client
16+
to share metrics between processes.
17+
"""
18+
shutil.rmtree(settings.PROMETHEUS_DIR, ignore_errors=True)
19+
Path(settings.PROMETHEUS_DIR).mkdir(parents=True)
20+
os.environ["PROMETHEUS_MULTIPROC_DIR"] = str(
21+
settings.PROMETHEUS_DIR.expanduser().absolute(),
22+
)
23+
24+
25+
def main() -> None:
26+
"""Entrypoint of the application."""
27+
set_multiproc_dir()
28+
29+
uvicorn.run(
30+
"app.api.application:get_app",
31+
workers=settings.WORKERS,
32+
host=settings.HOST,
33+
port=settings.PORT,
34+
reload=settings.RELOAD,
35+
log_level=settings.LOG_LEVEL.value.lower(),
36+
factory=True,
37+
)
38+
39+
40+
if __name__ == "__main__":
41+
main()

app/api/application.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from pathlib import Path
2+
3+
from fastapi import FastAPI
4+
from fastapi.middleware.cors import CORSMiddleware
5+
from fastapi.responses import JSONResponse
6+
from fastapi.staticfiles import StaticFiles
7+
8+
from app.api.lifespan import lifespan_setup
9+
from app.api.v1.api import api_router
10+
from app.core.config import settings
11+
from app.core.log import configure_logging
12+
13+
APP_ROOT = Path(__file__).parent.parent
14+
15+
16+
def get_app() -> FastAPI:
17+
"""Get FastAPI application."""
18+
configure_logging()
19+
20+
app = FastAPI(
21+
title=settings.PROJECT_NAME,
22+
version="0.0.1",
23+
docs_url=None,
24+
redoc_url=None,
25+
openapi_url=f"{settings.API_V1_STR}/openapi.json",
26+
lifespan=lifespan_setup,
27+
default_response_class=JSONResponse,
28+
)
29+
30+
app.add_middleware(
31+
CORSMiddleware,
32+
allow_origins=settings.CORS_ORIGINS,
33+
allow_credentials=True,
34+
allow_methods=["*"],
35+
allow_headers=["*"],
36+
)
37+
38+
app.include_router(api_router, prefix=settings.API_V1_STR)
39+
40+
# Adds static directory. This directory is used to access swagger files.
41+
app.mount("/static", StaticFiles(directory=APP_ROOT / "static"), name="static")
42+
43+
return app
File renamed without changes.

app/api/v1/api.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
from fastapi import APIRouter, Depends
22

3-
from app.api.v1.endpoints import auth, docs, items, users
3+
from app.api.v1.endpoints import auth, docs, health, items, users
44
from app.dependencies.auth import get_current_user
55

66
api_router = APIRouter()
7+
78
api_router.include_router(docs.router)
8-
api_router.include_router(auth.router, prefix="/auth", tags=["auth"])
9+
api_router.include_router(health.router)
10+
11+
api_router.include_router(
12+
auth.router,
13+
prefix="/auth",
14+
tags=["auth"],
15+
)
916
api_router.include_router(
1017
users.router,
1118
prefix="/users",

app/api/v1/endpoints/health.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from fastapi import APIRouter
2+
3+
router = APIRouter()
4+
5+
6+
@router.get("/health")
7+
def health_check() -> None:
8+
"""Checks the health of a project.
9+
10+
It returns 200 if the project is healthy.
11+
"""

app/api/v1/endpoints/items.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
from typing import Annotated, Optional
1+
from typing import Annotated
22

33
from fastapi import APIRouter, Depends, Query
44

5-
# from pydantic import Field
65
from app.dependencies.repositories import get_item_service
76
from app.models.item import Item, ItemCreate, ItemUpdate
87
from app.services.item_service import ItemService
@@ -13,13 +12,16 @@
1312
@router.get("/")
1413
async def get_items( # noqa: PLR0913
1514
item_service: Annotated[ItemService, Depends(get_item_service)],
16-
skip: int = Query(0, ge=0, description="Number of items to skip"),
17-
# skip: int = Field(0, ge=0, description="Number of items to skip"), # FIXME: Not working
18-
limit: int = Query(100, ge=1, le=100, description="Number of items to return"),
19-
name: Optional[str] = Query(None, description="Filter items by name"),
20-
description: Optional[str] = Query(None, description="Filter items by description"),
21-
sort_by: Optional[str] = Query(None, description="Field to sort by"),
22-
order: Optional[str] = Query("asc", description="Sort order (asc or desc)"),
15+
skip: Annotated[int, Query(ge=0, description="Number of items to skip")] = 0,
16+
limit: Annotated[
17+
int, Query(ge=1, le=100, description="Number of items to return")
18+
] = 100,
19+
name: Annotated[str | None, Query(description="Filter items by name")] = None,
20+
description: Annotated[
21+
str | None, Query(description="Filter items by description")
22+
] = None,
23+
sort_by: Annotated[str | None, Query(description="Field to sort by")] = None,
24+
order: Annotated[str | None, Query(description="Sort order (asc or desc)")] = "asc",
2325
) -> list[Item]:
2426
return item_service.get_items(
2527
skip=skip,
@@ -29,7 +31,6 @@ async def get_items( # noqa: PLR0913
2931
sort_by=sort_by,
3032
order=order,
3133
)
32-
# return {"message": "Get all items"}
3334

3435

3536
@router.get("/{item_id}")

app/core/config.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
from enum import StrEnum
2+
from pathlib import Path
3+
from tempfile import gettempdir
24
from typing import Annotated
35

4-
from pydantic import (
5-
AfterValidator,
6-
AnyHttpUrl,
7-
PlainValidator,
8-
TypeAdapter,
9-
)
6+
from pydantic import AfterValidator, AnyHttpUrl, Field, PlainValidator, TypeAdapter
107
from pydantic_settings import BaseSettings
118

9+
TEMP_DIR = Path(gettempdir())
10+
1211
AnyHttpUrlAdapter = TypeAdapter(AnyHttpUrl)
1312

1413
CustomHttpUrlStr = Annotated[
@@ -45,6 +44,10 @@ class Settings(BaseSettings):
4544
TELEMETRY_ENABLED: bool = False
4645
TELEMETRY_LOGGING_ENABLED: bool = False
4746
WORKERS: int = 1
47+
PROMETHEUS_DIR: Path = Field(
48+
default=TEMP_DIR / "prom",
49+
description="This variable is used to define multiproc_dir.It's required for [uvi|guni]corn projects.",
50+
)
4851

4952
class Config:
5053
case_sensitive = True
File renamed without changes.

app/main.py

Lines changed: 0 additions & 56 deletions
This file was deleted.

0 commit comments

Comments
 (0)