Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b51a0a5

Browse files
committedFeb 21, 2023
add a simple flask api which uses duckdb
0 parents  commit b51a0a5

File tree

8 files changed

+120
-0
lines changed

8 files changed

+120
-0
lines changed
 

‎.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# created by virtualenv automatically
2+
local/

‎Dockerfile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
FROM python:3.10.8-slim
2+
3+
RUN apt-get update && apt-get upgrade -y
4+
5+
WORKDIR /app
6+
7+
COPY requirements.txt /app/requirements.txt
8+
9+
RUN pip install -r requirements.txt
10+
11+
COPY server.py /app/server.py
12+
13+
COPY test.db /app/test.db
14+
15+
EXPOSE 8080
16+
17+
CMD ["python", "server.py"]

‎Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
build:
2+
pip3 install -r requirements.txt
3+
4+
run: build
5+
python3 server.py
6+
7+
docker.build:
8+
./build_image.sh
9+
10+
docker.run:
11+
docker run --rm -it --name python-api -p 8080:8080 python-api:latest

‎Readme.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Containerized Python API using DuckDB
2+
Sample Containerized Python API using [DuckDB](https://duckdb.org/)
3+
4+
## Flask API
5+
The service exposes `GET http://localhost:8080/stats` api which returns aggregated user count from DuckDB database `test.duckdb`.
6+
7+
**API response:**
8+
```json
9+
[
10+
{
11+
"date": "2021-02-20",
12+
"users_joined": 2598
13+
},
14+
{
15+
"date": "2021-02-21",
16+
"users_joined": 2578
17+
}
18+
]
19+
```
20+
21+
## Running without docker
22+
```bash
23+
make run
24+
```
25+
26+
## Running as a container
27+
```bash
28+
# builds docker image
29+
make docker.build
30+
31+
# runs docker image
32+
make docker.run
33+
```
34+
35+
## Test Data
36+
Test data is coming from database file `test.duckdb`. It contains a table called `users` which has following fields with ~1 million randomly generated rows:
37+
38+
| id (int32)| joined_date (date) | name (varchar)| email (varchar) |
39+
|-----------|--------------------|---------------|-------------------------|
40+
| 1 | 2021-09-14 | Jarret Kuhn | carsondooley@wolf.name |

‎build_image.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/sh
2+
3+
if [[ $(uname -m) == *"arm"* ]]; then
4+
BUILD_PLATFORM="--platform linux/amd64"
5+
fi
6+
7+
docker build $BUILD_PLATFORM -t python-api .
8+
9+
echo "cleaning up old docker images..."
10+
docker system prune -f

‎requirements.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
click==8.1.3
2+
distlib==0.3.6
3+
duckdb==0.7.0
4+
filelock==3.9.0
5+
Flask==2.2.3
6+
itsdangerous==2.1.2
7+
Jinja2==3.1.2
8+
MarkupSafe==2.1.2
9+
platformdirs==3.0.0
10+
virtualenv==20.19.0
11+
Werkzeug==2.2.3

‎server.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from flask import Flask
2+
import duckdb, json
3+
4+
app = Flask(__name__)
5+
db = duckdb.connect(database='test.duckdb', read_only=True)
6+
7+
@app.route('/stats', methods=['GET'])
8+
def stats():
9+
db.execute("""
10+
SELECT
11+
CAST(joined_date AS VARCHAR) as date,
12+
MAX(row_number) as users_joined
13+
FROM (
14+
SELECT
15+
joined_date,
16+
ROW_NUMBER() OVER (PARTITION BY joined_date) as row_number
17+
FROM users
18+
WHERE joined_date BETWEEN (now()::TIMESTAMP - INTERVAL '2 years') AND now()
19+
) GROUP BY joined_date
20+
ORDER BY joined_date ASC;
21+
""")
22+
stats = db.fetchall()
23+
24+
columns = ['date', 'users_joined']
25+
items = [dict(zip(columns, row)) for row in stats]
26+
return json.dumps(items)
27+
28+
if __name__ == '__main__':
29+
app.run(port=8080, host='0.0.0.0')

‎test.duckdb

69.8 MB
Binary file not shown.

0 commit comments

Comments
 (0)
Please sign in to comment.