Archived
feat: initialize FastAPI project structure with job posting routes and models
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
from .logger import logger
|
||||
from .settings import settings
|
||||
|
||||
__all__ = ["logger", "settings"]
|
||||
@@ -0,0 +1,9 @@
|
||||
from fastapi import HTTPException, status
|
||||
|
||||
|
||||
class NotImplementedException(HTTPException):
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
status_code=status.HTTP_501_NOT_IMPLEMENTED,
|
||||
detail="Not implemented yet",
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
from loguru import logger
|
||||
from sys import stdout
|
||||
|
||||
from .settings import settings
|
||||
|
||||
logger.remove()
|
||||
|
||||
logger.add(
|
||||
stdout,
|
||||
format="{time:YYYY-MM-DD at HH:mm:ss} | {file}:{line} | <level>{level}</level> | {message} | {extra}",
|
||||
colorize=True,
|
||||
enqueue=True,
|
||||
)
|
||||
|
||||
logger.add(
|
||||
settings.log_dir / "file.log",
|
||||
format="",
|
||||
serialize=True,
|
||||
level="INFO",
|
||||
rotation="10 MB",
|
||||
retention="1 week",
|
||||
enqueue=True,
|
||||
compression="gz",
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
from pydantic_settings import BaseSettings
|
||||
from pydantic import Field
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
data_dir: Path = Field(default=Path(__file__).parent.parent / "data")
|
||||
|
||||
@property
|
||||
def log_dir(self) -> Path:
|
||||
dir = self.data_dir / "logs"
|
||||
if not dir.is_dir():
|
||||
dir.mkdir(parents=True, exist_ok=True)
|
||||
return dir
|
||||
|
||||
|
||||
settings = Settings()
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
from fastapi import FastAPI
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from routes import routes
|
||||
from lib import logger
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
# Startup code here
|
||||
logger.info("Application startup")
|
||||
yield
|
||||
# Shutdown code here
|
||||
logger.info("Application shutdown")
|
||||
|
||||
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
|
||||
|
||||
for route in routes:
|
||||
app.include_router(route)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
|
||||
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class JobListing(BaseModel):
|
||||
title: str = Field(..., description="Job title")
|
||||
company: str = Field(..., description="Company name")
|
||||
location: str = Field(..., description="Location")
|
||||
description: str = Field(..., description="Job description")
|
||||
salary: int | None = Field(None, description="Salary")
|
||||
url: str = Field(..., description="Job URL")
|
||||
@@ -0,0 +1,36 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from datetime import datetime
|
||||
from zoneinfo import ZoneInfo
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class _Type(Enum):
|
||||
INFO = "info"
|
||||
WARNING = "warning"
|
||||
ERROR = "error"
|
||||
SUCCESS = "success"
|
||||
|
||||
|
||||
class _Message(BaseModel):
|
||||
msg: str = Field(..., description="Message")
|
||||
|
||||
timestamp: datetime = Field(
|
||||
default_factory=lambda: datetime.now(tz=ZoneInfo("UTC")),
|
||||
description="Timestamp",
|
||||
)
|
||||
|
||||
|
||||
class Error(_Message):
|
||||
msg_type: _Type = _Type.ERROR
|
||||
|
||||
|
||||
class Warning(_Message):
|
||||
msg_type: _Type = _Type.WARNING
|
||||
|
||||
|
||||
class Info(_Message):
|
||||
msg_type: _Type = _Type.INFO
|
||||
|
||||
|
||||
class Success(_Message):
|
||||
msg_type: _Type = _Type.SUCCESS
|
||||
@@ -0,0 +1,6 @@
|
||||
from .default import router as default_router
|
||||
from .job_postings import router as job_postings_router
|
||||
|
||||
routes = [default_router, job_postings_router]
|
||||
|
||||
__all__ = ["routes"]
|
||||
@@ -0,0 +1,14 @@
|
||||
from fastapi import APIRouter
|
||||
from models.message import Success
|
||||
|
||||
router = APIRouter(tags=["Default"])
|
||||
|
||||
|
||||
@router.get("/")
|
||||
def root():
|
||||
return Success(msg="Hello World")
|
||||
|
||||
|
||||
@router.get("/health")
|
||||
def health():
|
||||
return Success(msg="ok")
|
||||
@@ -0,0 +1,31 @@
|
||||
from fastapi import APIRouter
|
||||
from enum import Enum
|
||||
|
||||
from lib.exceptions import NotImplementedException
|
||||
from lib import logger
|
||||
|
||||
router = APIRouter(prefix="/job_postings", tags=["Job Postings"])
|
||||
|
||||
|
||||
class PostingSource(Enum):
|
||||
ALL = "all"
|
||||
LINKEDIN = "linkedin"
|
||||
DUUNITORI = "duunitori"
|
||||
TYOMARKKINATORI = "tyomarkkinatori"
|
||||
|
||||
|
||||
@router.get("/")
|
||||
def get_job_postings(source: PostingSource = PostingSource.ALL):
|
||||
match source:
|
||||
case PostingSource.ALL:
|
||||
logger.error(f"Job postings from {source.value} Not implemented yet")
|
||||
raise NotImplementedException()
|
||||
case PostingSource.LINKEDIN:
|
||||
logger.error(f"Job postings from {source.value} Not implemented yet")
|
||||
raise NotImplementedException()
|
||||
case PostingSource.DUUNITORI:
|
||||
logger.error(f"Job postings from {source.value} Not implemented yet")
|
||||
raise NotImplementedException()
|
||||
case PostingSource.TYOMARKKINATORI:
|
||||
logger.error(f"Job postings from {source.value} Not implemented yet")
|
||||
raise NotImplementedException()
|
||||
Reference in New Issue
Block a user