Skip to content

Commit 22581cb

Browse files
committed
initial commit
0 parents  commit 22581cb

File tree

10 files changed

+473
-0
lines changed

10 files changed

+473
-0
lines changed

README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# javascript-web-htmx-get-nunjunk-python-flask-api-surrealdb-simple
2+
3+
## Description
4+
A demo of htmx using a python flask
5+
api to return contents of table from
6+
surrealdb.
7+
8+
## Tech stack
9+
- htmx
10+
- get
11+
- ext
12+
- swap
13+
- target
14+
- nunjunk
15+
- python
16+
- flask
17+
- cors
18+
- surrealdb
19+
20+
## Docker stack
21+
- httpd:latest
22+
- python:latest
23+
- surrealdb/surrealdb:latest
24+
25+
## To run
26+
`sudo ./install.sh -u`
27+
- Available at http://localhost
28+
29+
## To stop
30+
`sudo ./install.sh -d`
31+
32+
## To see help
33+
`sudo ./install.sh -h`
34+
35+
## Credit
36+
- [Htmx clientside template](https://htmx.org/extensions/client-side-templates/)
37+
- [Htmx rendering JSON](https://marcus-obst.de/blog/htmx-json-handling)

api/Dockerfile

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
FROM python:latest
3+
4+
COPY bin/ /app
5+
6+
WORKDIR /app
7+
8+
RUN pip install --upgrade pip
9+
10+
RUN pip install -r requirements.txt
11+
12+
ENV WAIT_VERSION 2.7.2
13+
14+
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/$WAIT_VERSION/wait /wait
15+
16+
RUN chmod +x /wait
17+
18+
CMD ["python", "app.py"]

api/bin/__init__.py

Whitespace-only changes.

api/bin/app.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from flask import Flask, request
2+
import logging
3+
from client import Endpoint
4+
from flask_cors import CORS
5+
6+
app = Flask(__name__)
7+
CORS(app)
8+
9+
logging.basicConfig(level=logging.INFO)
10+
11+
@app.route('/')
12+
def smoke_test():
13+
d = {'hello': 'world'}
14+
return {'results': d}
15+
16+
@app.route('/dog')
17+
async def get_all():
18+
results = await endpoint.get_all()
19+
return {'results': results}
20+
21+
@app.route('/dog/breed/<string:breed>', methods=['GET', 'DELETE', 'POST'])
22+
async def filter_del_upd_by_breed(breed: str):
23+
results = []
24+
if request.method == 'GET':
25+
results = await endpoint.filter_by('breed', breed)
26+
elif request.method == 'DELETE':
27+
results = await endpoint.delete('breed', breed)
28+
elif request.method == 'POST':
29+
results = await endpoint.update('breed', breed)
30+
return {'results': results}
31+
32+
@app.route('/dog/color/<string:color>', methods=['GET', 'DELETE', 'POST'])
33+
async def filter_del_upd_by_color(color: str):
34+
results = []
35+
if request.method == 'GET':
36+
results = await endpoint.filter_by('color', color)
37+
elif request.method == 'DELETE':
38+
results = await endpoint.delete('color', color)
39+
elif request.method == 'POST':
40+
results = await endpoint.update('color', color)
41+
return {'results': results}
42+
43+
@app.route('/dog/my_id/<string:id>', methods=['GET', 'DELETE', 'POST'])
44+
async def filter_del_upd_by_id(id: str):
45+
results = []
46+
if request.method == 'GET':
47+
results = await endpoint.filter_by('my_id', id)
48+
elif request.method == 'DELETE':
49+
results = await endpoint.delete('my_id', id)
50+
elif request.method == 'POST':
51+
results = await endpoint.update('my_id', id)
52+
return {'results': results}
53+
54+
@app.route('/dog/breed/<breed>/color/<color>', methods=['PUT'])
55+
async def ins_by_breed(breed: str, color: str):
56+
results = await endpoint.insert(breed, color)
57+
return {'results': results}
58+
59+
if __name__ == "__main__":
60+
endpoint = Endpoint()
61+
app.run(host ='0.0.0.0', port = 5000, debug = True)

api/bin/client.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
from surrealdb import Surreal
2+
import logging
3+
4+
logging.basicConfig(level=logging.INFO)
5+
6+
class SurrealClient:
7+
8+
def __init__(self) -> None:
9+
self.isSeeded = False
10+
11+
async def query(self, sql):
12+
host = "db"
13+
port = 8000
14+
async with Surreal(f"ws://{host}:{port}/rpc") as db:
15+
await db.signin({"user": "root", "pass": "pass"})
16+
await db.use("test", "test")
17+
x = await db.query(sql)
18+
return x[0]['result']
19+
20+
21+
async def seed(self):
22+
if self.isSeeded == True:
23+
return
24+
25+
results = []
26+
records = [
27+
{ "breed": "Am Bulldog", "color": "White", "my_id": '1' },
28+
{ "breed": "Blue Tick", "color": "Grey", "my_id": '2' },
29+
{ "breed": "Labrador", "color": "Black", "my_id": '3' },
30+
{ "breed": "Gr Shepard", "color": "Brown", "my_id": '4' }
31+
]
32+
for record in records:
33+
sql = "insert into dog {"
34+
for k, v in record.items():
35+
sql += f"{k}: '{v}',"
36+
sql += "};"
37+
results.append(await self.query(sql))
38+
39+
self.isSeeded = True
40+
41+
return results
42+
43+
class Endpoint:
44+
"""Create singleton"""
45+
def __new__(cls):
46+
if not hasattr(cls, 'instance'):
47+
cls.instance = super(Endpoint, cls).__new__(cls)
48+
return cls.instance
49+
50+
def __init__(self) -> None:
51+
self.client = SurrealClient()
52+
53+
async def get_all(self):
54+
await self.client.seed()
55+
sql = 'select * from dog'
56+
return await self.client.query(sql)
57+
58+
async def filter_by(self, filter, filter_val):
59+
await self.client.seed()
60+
sql = f'select * from dog where {filter} = "{filter_val}"'
61+
return await self.client.query(sql)
62+
63+
async def delete(self, filter, filter_val):
64+
await self.client.seed()
65+
sql = f'delete from dog where {filter} = "{filter_val}"'
66+
await self.client.query(sql)
67+
return await self.get_all()
68+
69+
async def insert(self, new_breed, new_color):
70+
await self.client.seed()
71+
records = [
72+
{ "breed": new_breed, "color": new_color, "my_id": '0' }
73+
]
74+
75+
sql = ''
76+
for record in records:
77+
sql = "insert into dog {"
78+
for k, v in record.items():
79+
sql += f"{k}: '{v}',"
80+
sql += "};"
81+
await self.client.query(sql)
82+
return await self.get_all()
83+
84+
async def update(self, filter, filter_val):
85+
await self.client.seed()
86+
logging.info(f"filter: {filter}, value: {filter_val}")
87+
sql = f"update dog set breed='updated', color='updated', my_id='99' where {filter} = '{filter_val}';"
88+
await self.client.query(sql)
89+
return await self.get_all()

api/bin/requirements.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Flask[async]
2+
flask-cors
3+
aioflask
4+
surrealdb

docker-compose.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
version: "3.4"
2+
3+
services:
4+
web:
5+
image: httpd:latest
6+
volumes:
7+
- ./web/bin:/usr/local/apache2/htdocs
8+
ports:
9+
- 80:80
10+
11+
db:
12+
image: surrealdb/surrealdb:latest
13+
command: start --log info --user root --pass pass file:/mydata
14+
ports:
15+
- 8000
16+
17+
api:
18+
build: api
19+
healthcheck:
20+
test: "exit 0"
21+
command: sh -c "/wait && python app.py"
22+
environment:
23+
- WAIT_HOSTS=db:8000
24+
- WAIT_HOSTS_TIMEOUT=300
25+
- WAIT_SLEEP_INTERVAL=30
26+
- WAIT_HOST_CONNECT_TIMEOUT=30
27+
depends_on:
28+
- db
29+
links:
30+
- "db:db"
31+
ports:
32+
- "81:5000"

general.log

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[2023-07-13 23:16:12 INFO]: install::setup-logging ended
2+
================
3+
[2023-07-13 23:16:12 INFO]: install::start-up started
4+
[2023-07-13 23:16:12 INFO]: install::start-up starting services
5+
[2023-07-13 23:18:01 INFO]: install::root-check started
6+
[2023-07-13 23:18:01 INFO]: install::root-check ended
7+
================
8+
[2023-07-13 23:18:01 INFO]: install::docker-check started
9+
[2023-07-13 23:18:01 INFO]: install::docker-check ended
10+
================
11+
[2023-07-13 23:18:01 INFO]: install::docker-compose-check started
12+
[2023-07-13 23:18:01 INFO]: install::docker-compose-check ended
13+
================
14+
[2023-07-13 23:18:01 INFO]: install::tear-down started
15+
[2023-07-13 23:18:01 INFO]: install::tear-down starting services
16+
[2023-07-13 23:18:01 INFO]: install::tear-down ended
17+
================

0 commit comments

Comments
 (0)