Skip to content

Commit

Permalink
merge fast-api
Browse files Browse the repository at this point in the history
  • Loading branch information
sgmdlt committed Nov 2, 2024
2 parents b2caedc + 5fa71fd commit 8c1bd48
Show file tree
Hide file tree
Showing 7 changed files with 633 additions and 72 deletions.
2 changes: 0 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ RUN apt-get update && \
apt-get install -y make && \
pip install uv

ENV UV_COMPILE_BYTECODE=1

WORKDIR /app
COPY . .
RUN make install
Expand Down
12 changes: 6 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,24 @@ install:
uv sync

dev:
uv run flask --app app.server run --debug -h 0.0.0.0 -p $(PORT)
uv run fastapi dev app/server.py --host 0.0.0.0 --port $(PORT)

run:
uv run gunicorn -w 4 -b 0.0.0.0:$(PORT) app.server:app
uv run uvicorn --workers 4 --host 0.0.0.0 --port $(PORT) app.server:app

build:
docker build . --tag=data-charts-api

start:
-docker stop data-charts-api
-docker rm data-charts-api
-docker stop data-charts-api || true
-docker rm data-charts-api || true
docker run -d --name data-charts-api -p $(PORT):$(PORT) data-charts-api

stop:
-docker stop data-charts-api
-docker stop data-charts-api || true

rm:
-docker rm data-charts-api
-docker rm data-charts-api || true

bash:
docker run --rm -it data-charts-api bash
Expand Down
116 changes: 70 additions & 46 deletions app/server.py
Original file line number Diff line number Diff line change
@@ -1,64 +1,88 @@
import logging
import os
import traceback
from contextlib import asynccontextmanager
from datetime import datetime

import psycopg
import asyncpg
from dotenv import load_dotenv
from flask import Flask, request
from psycopg.rows import dict_row
from fastapi import Depends, FastAPI, HTTPException, Query
from fastapi.middleware.gzip import GZipMiddleware
from fastapi_cache import FastAPICache
from fastapi_cache.backends.inmemory import InMemoryBackend
from fastapi_cache.decorator import cache

load_dotenv()

DATABASE_URL = os.getenv('DATABASE_URL')

app = Flask(__name__)
app.config['DATABASE_URL'] = os.getenv('DATABASE_URL')
@asynccontextmanager
async def lifespan(app: FastAPI):
app.state.pool = await asyncpg.create_pool(
DATABASE_URL,
min_size=5,
max_size=20
)
FastAPICache.init(InMemoryBackend())
yield
await app.state.pool.close()

app = FastAPI(lifespan=lifespan)
app.add_middleware(GZipMiddleware, minimum_size=1000)

def get_db():
return psycopg.connect(app.config['DATABASE_URL'])
async def get_db():
async with app.state.pool.acquire() as conn:
yield conn


@app.route('/')
def index():
return 'It Works'
@app.get("/")
async def index():
return {"status": "It Works"}


@app.get('/visits')
def get_visits():
query = request.args
@app.get("/visits")
@cache(expire=300)
async def get_visits(
begin: str = Query(..., description="Start date in ISO format"),
end: str = Query(..., description="End date in ISO format"),
db = Depends(get_db)
):
begin = datetime.fromisoformat(begin)
end = datetime.fromisoformat(end)
try:
begin_date = datetime.fromisoformat(query['begin'])
end_date = datetime.fromisoformat(query['end'])
except ValueError as e:
logging.error(traceback.format_exc(2, chain=False))
return 'Invalid date. Please check your input', 400
query = '''
SELECT *
FROM visits
WHERE visits.datetime BETWEEN (%s) AND (%s);'''
with get_db() as conn:
with conn.cursor(row_factory=dict_row) as c:
c.execute(query, [begin_date, end_date])
res = c.fetchall()
return res
query = """
SELECT *
FROM visits
WHERE visits.datetime BETWEEN $1 AND $2
"""
records = await db.fetch(query, begin, end)
return records
except Exception as e:
logging.error(f"Error fetching visits: {str(e)}")
raise HTTPException(
status_code=500,
detail="Internal server error occurred while fetching visits"
)


@app.get('/registrations')
def get_registrations():
query = request.args
@app.get("/registrations")
@cache(expire=300)
async def get_registrations(
begin: str = Query(..., description="Start date in ISO format"),
end: str = Query(..., description="End date in ISO format"),
db = Depends(get_db)
):
begin = datetime.fromisoformat(begin)
end = datetime.fromisoformat(end)
try:
begin_date = datetime.fromisoformat(query['begin'])
end_date = datetime.fromisoformat(query['end'])
except ValueError as e:
logging.error(traceback.format_exc(2, chain=False))
return 'Invalid date. Please check your input', 400
query = '''
SELECT *
FROM registrations
WHERE registrations.datetime BETWEEN (%s) AND (%s);'''
with get_db() as conn:
with conn.cursor(row_factory=dict_row) as c:
c.execute(query, [begin_date, end_date])
res = c.fetchall()
return res
query = """
SELECT *
FROM registrations
WHERE registrations.datetime BETWEEN $1 AND $2
"""
records = await db.fetch(query, begin, end)
return records
except Exception as e:
logging.error(f"Error fetching registrations: {str(e)}")
raise HTTPException(
status_code=500,
detail="Internal server error occurred while fetching registrations"
)
Empty file removed docker-compose.yml
Empty file.
12 changes: 4 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ description = "api for data charts project"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"asyncpg>=0.30.0",
"fastapi-cache2>=0.2.2",
"fastapi[standard]>=0.115.4",
"flask>=3.0.3",
"gunicorn>=23.0.0",
"psycopg[binary]>=3.2.3",
"python-dotenv>=1.0.1",
"uvicorn>=0.32.0",
]

[tool.uv]
Expand All @@ -17,10 +20,3 @@ dev-dependencies = [
"requests>=2.32.3",
"ruff>=0.7.2",
]

[tool.hatch.build.targets.wheel]
packages = ["app"]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
4 changes: 2 additions & 2 deletions tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
def test_server():
response = requests.get('http://localhost:4000/')
assert response.status_code == 200
assert response.text == 'It Works'
assert response.json()['status'] == 'It Works'

response = requests.get('http://localhost:4000/visits?begin=2023-03-01&end=2023-03-02')
assert response.status_code == 200
assert response.json()[0] == {
"datetime": "Wed, 01 Mar 2023 10:36:22 GMT",
"datetime": "2023-03-01T10:36:22",
"platform": "web",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.6",
"visit_id": "1de9ea66-70d3-4a1f-8735-df5ef7697fb9"
Expand Down
Loading

0 comments on commit 8c1bd48

Please sign in to comment.