Python RestAPI using Quart HTTP/3 ASGI framework.
- On a development host, create a virtual environment for development and test. Both must be using the same virtual environment.
- Virtual environment is optional for CI/CD do because everything runs in a docker container.
- Add the following to
.env
for database access credentials:
DB_USERNAME=username
DB_PASSWORD=password
- Obtain an API key from https://aistudio.google.com/apikey
- Add a
.env
file with the following content:GEMINI_API_KEY=<api key>
pipenv --rm
pipenv --clear
pipenv lock --clear --verbose
$ pipenv install
$ pipenv shell
- This project uses PostgreSQL database with SQLAlchemy ORM with marshmallow for object SerDes.
$ pipenv install --python=/path/to/python
$ cd src
$ pipenv install --python=/path/to/python
$ cd test
$ pipenv install --python=/path/to/python
- Firstly, create an empty database "library" in PostgreSQL
-
Copy
env.py
tomigrations/
folder. -
Set the values
DB_foo
in/etc/pythonrestapi_config.json
-
run migrations initialization with db init command:
$ pipenv run alembic init migrations $ cp env.py migrations $ pipenv run alembic revision --autogenerate -m "Initial migration" $ pipenv run alembic upgrade head
-
There will be 3 tables, "users", "books", and "authors" created in the PostgreSQL database "library" after the
upgrade
.
- There are 7 test cases
- JWT token generation and decoding
- HomeController
- FibonacciController
$ pipenv run pytest -v $ python -m pytest
- Integrated with CircleCI
./hypercorn.sh
- To build your own HTTP/3 curl: https://curl.se/docs/http3.html
- Add
Host
header which is defined asserver_names
inhypercorn.toml
curl --http3-only --insecure -v https://localhost:4433/<path> -H "Host: khteh.com"
curl --http3-only --insecure -vv https://localhost:4433/chat/invoke -F 'prompt=:"What is task decomposition?"' -F 'file=@~/data/1.jpg' -F 'receipt=true'
-
Close ALL chrome browser (both tabs and windows)
-
Generate TLS certificate fingerprint:
$ fingerprint=`openssl x509 -pubkey -noout -in /tmp/server.crt |
openssl rsa -pubin -outform der |
openssl dgst -sha256 -binary | base64`
- Start Chrome browser with QUIC protocol for HTTP/3:
$1
is URL. For example:https://localhost:4433
$ /opt/google/chrome/chrome --disable-setuid-sandbox --enable-quic --ignore-certificate-errors-spki-list=$fingerprint --origin-to-force-quic-on=${1#*//} $1
- Return text message from input prompt string by calling the API
- Return text message from input prompt string and an image file by calling the API
- Multimodal:
- Upload an image, "receipt" in this case, and it wil return a structured data containing details in the receipt:
2025-05-21 13:15:34 DEBUG ProcessReceipt response: { "date_str": "28-07-2017", "vendor": "Walmart", "currency": "USD", "items": [ { "name": "PET TOY", "amount": 1.97 }, { "name": "FLOPPY PUPPY", "amount": 1.97 }, { "name": "SSSUPREME S", "amount": 4.97 }, { "name": "2.5 SQUEAK", "amount": 5.92 }, { "name": "MUNCHY DMBEL", "amount": 3.77 }, { "name": "DOG TREAT", "amount": 2.92 }, { "name": "PED PCH 1", "amount": 0.50 }, { "name": "PED PCH 1", "amount": 0.50 }, { "name": "COUPON 23100", "amount": 1.00 }, { "name": "HNYMD SMORES", "amount": 3.98 }, { "name": "FRENCH DRSNG", "amount": 1.98 }, { "name": "3 ORANGES", "amount": 5.47 }, { "name": "BABY CARROTS", "amount": 1.48 }, { "name": "COLLARDS", "amount": 1.24 }, { "name": "CALZONE", "amount": 2.50 }, { "name": "MM RVW MNT", "amount": 19.77 }, { "name": "STKOBRLPLABL", "amount": 1.97 }, { "name": "STKOBRLPLABL", "amount": 1.97 }, { "name": "STKO SUNFLWR", "amount": 0.97 }, { "name": "STKO SUNFLWR", "amount": 0.97 }, { "name": "STKO SUNFLWR", "amount": 0.97 }, { "name": "STKO SUNFLWR", "amount": 0.97 }, { "name": "BLING BEADS", "amount": 0.97 }, { "name": "GREAT VALUE", "amount": 9.97 }, { "name": "LIPTON", "amount": 4.48 }, { "name": "DRY DOG", "amount": 12.44 } ], "tax": 4.59, "total": 98.21 }, receipt: vendor='Walmart' currency='USD' items=[ReceiptItem(name='PET TOY', amount=1.97), ReceiptItem(name='FLOPPY PUPPY', amount=1.97), ReceiptItem(name='SSSUPREME S', amount=4.97), ReceiptItem(name='2.5 SQUEAK', amount=5.92), ReceiptItem(name='MUNCHY DMBEL', amount=3.77), ReceiptItem(name='DOG TREAT', amount=2.92), ReceiptItem(name='PED PCH 1', amount=0.5), ReceiptItem(name='PED PCH 1', amount=0.5), ReceiptItem(name='COUPON 23100', amount=1.0), ReceiptItem(name='HNYMD SMORES', amount=3.98), ReceiptItem(name='FRENCH DRSNG', amount=1.98), ReceiptItem(name='3 ORANGES', amount=5.47), ReceiptItem(name='BABY CARROTS', amount=1.48), ReceiptItem(name='COLLARDS', amount=1.24), ReceiptItem(name='CALZONE', amount=2.5), ReceiptItem(name='MM RVW MNT', amount=19.77), ReceiptItem(name='STKOBRLPLABL', amount=1.97), ReceiptItem(name='STKOBRLPLABL', amount=1.97), ReceiptItem(name='STKO SUNFLWR', amount=0.97), ReceiptItem(name='STKO SUNFLWR', amount=0.97), ReceiptItem(name='STKO SUNFLWR', amount=0.97), ReceiptItem(name='STKO SUNFLWR', amount=0.97), ReceiptItem(name='BLING BEADS', amount=0.97), ReceiptItem(name='GREAT VALUE', amount=9.97), ReceiptItem(name='LIPTON', amount=4.48), ReceiptItem(name='DRY DOG', amount=12.44)] tax=4.59 total=98.21 date_of_receipt=datetime.date(2017, 7, 28)
- POST https://localhost:4433/users/create with the following JSON data:
{ "firstname": "First Name", "lastname": "LastName", "email": "[email protected]", "password": "P@$$w0rd" }
- POST https://localhost:4433/users/login with the following JSON data:
{ "email": "[email protected]", "password": "P@$$w0rd" }
- Sample response:
{ "jwt_token": "token string" }
Key: api-key
Vaue: jwt_token from the login response
- POST https://localhost:4433/authors/create with the following JSON data:
{ "email": "[email protected]", "firstname": "JK", "lastname": "Rowing" }
- POST https://localhost:4433/books/create with the following JSON data:
{ "author_id": 1, "isbn": "123456", "page_count": "123", "title": "My First Book" }
- Books table has a foreign key id to Authors.id and this is defined as required in BookSchema.
- Therefore, when a DELETE RESTful operation is sent to the application to delete an author which has associated book:
mysql.connector.errors.IntegrityError: 1048 (23000): Column 'author_id' cannot be null
-
Headers:
Key: api-key Vaue: jwt_token from the login response
-
visit https://localhost:4433