diff --git a/Dockerfile.api b/Dockerfile.api new file mode 100644 index 0000000..ff7ba6d --- /dev/null +++ b/Dockerfile.api @@ -0,0 +1,15 @@ +FROM python:3.9-slim + +WORKDIR /app + +RUN apt-get update && apt-get install -y --no-install-recommends \ + gcc \ + libpq-dev \ + && rm -rf /var/lib/apt/lists/* + +COPY requirements.api.txt . +RUN pip install --no-cache-dir -r requirements.api.txt + +COPY src/api /app/api + +CMD ["uvicorn", "api.main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b19db84 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +.PHONY: up init-db down restart + +up: + docker-compose up -d + +init-db: + docker exec -it $$(docker ps -qf "name=api") python -c "\ +from api.database import Base, engine; \ +from api.models import Message; \ +Base.metadata.create_all(bind=engine)\ +" + +down: + docker-compose down + +restart: down up init-db \ No newline at end of file diff --git a/compose.yaml b/compose.yaml index 64d31f8..11d06b3 100644 --- a/compose.yaml +++ b/compose.yaml @@ -6,9 +6,21 @@ services: GROUP_ID: "group_id" ACCESS_TOKEN: "access_token" DATABASE_URL: "postgresql://postgres:password@db:5432/vkbot" - depends_on: - db - restart: unless-stopped + depends_on: + - db + restart: unless-stopped + + api: + build: + context: . + dockerfile: Dockerfile.api + environment: + DATABASE_URL: "postgresql://postgres:password@db:5432/vkbot" + ports: + - "8000:8000" + depends_on: + - db + restart: unless-stopped db: image: postgres:15 diff --git a/requirements.api.txt b/requirements.api.txt new file mode 100644 index 0000000..6292ee9 --- /dev/null +++ b/requirements.api.txt @@ -0,0 +1,4 @@ +fastapi +uvicorn +psycopg2-binary +sqlalchemy \ No newline at end of file diff --git a/src/api/database.py b/src/api/database.py new file mode 100644 index 0000000..56b77e4 --- /dev/null +++ b/src/api/database.py @@ -0,0 +1,17 @@ +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker +import os + +DATABASE_URL = os.getenv("DATABASE_URL") + +engine = create_engine(DATABASE_URL) +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) +Base = declarative_base() + +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() \ No newline at end of file diff --git a/src/api/main.py b/src/api/main.py new file mode 100644 index 0000000..a062f86 --- /dev/null +++ b/src/api/main.py @@ -0,0 +1,22 @@ +from fastapi import FastAPI, Depends +from sqlalchemy.orm import Session +from api.database import get_db +from api.models import Message +from fastapi.middleware.cors import CORSMiddleware + +app = FastAPI() + +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_methods=["*"], + allow_headers=["*"], +) + +@app.get("/messages") +def get_messages(order_by: str = "id", take: int = 10, skip: int = 0, db: Session = Depends(get_db)): + order_by_field = getattr(Message, order_by, None) + if order_by_field is None: + return {"error": f"Invalid order_by field: {order_by}"} + messages = db.query(Message).order_by(order_by_field).offset(skip).limit(take).all() + return messages \ No newline at end of file diff --git a/src/api/models.py b/src/api/models.py new file mode 100644 index 0000000..b954090 --- /dev/null +++ b/src/api/models.py @@ -0,0 +1,12 @@ +from sqlalchemy import Column, Integer, BigInteger, Text, TIMESTAMP +from api.database import Base + +class Message(Base): + __tablename__ = "messages" + + id = Column(Integer, primary_key=True, index=True) + user_id = Column(BigInteger) + peer_id = Column(BigInteger) + message_id = Column(BigInteger) + text = Column(Text) + timestamp = Column(TIMESTAMP) \ No newline at end of file