https://github.com/andgineer/api-db-prototype
API with SQL Alchemy layer alternatively implemented with Flask and Connexion
https://github.com/andgineer/api-db-prototype
alembic connexion flask flask-login jwt sqlalchemy
Last synced: 11 months ago
JSON representation
API with SQL Alchemy layer alternatively implemented with Flask and Connexion
- Host: GitHub
- URL: https://github.com/andgineer/api-db-prototype
- Owner: andgineer
- Created: 2018-11-06T15:28:08.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2025-02-18T16:57:38.000Z (11 months ago)
- Last Synced: 2025-02-18T17:38:02.521Z (11 months ago)
- Topics: alembic, connexion, flask, flask-login, jwt, sqlalchemy
- Language: Python
- Homepage:
- Size: 1.22 MB
- Stars: 1
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
[](https://github.com/andgineer/api-db-prototype/actions)
[](https://htmlpreview.github.io/?https://github.com/andgineer/api-db-prototype/blob/python-coverage-comment-action-data/htmlcov/index.html)
# API server experiment
This project is an experimental implementation of an API server using different approaches.
## Approaches
1. **Connexion - Spec First**
2. **Flask - Code First**
In both cases we use SQLAlchemy for DB access and Alembic for DB versioning, implement JWT auth.
And provide Swagger UI.
## Common Controllers
In this project, we're trying to create controllers (application logic)
that can be shared between the two different approaches we're using.
However, because of the way Connexion generates code, we can't use application objects in the
controllers parameters. We have to keep their signatures a bit more generic to work with both
approaches.
## Real-World Considerations
In a real-world project, it is advisable to choose a single approach and use it consistently.
Frameworks like FastAPI and LiteStar utilize Python type hinting to automatically generate
API specifications. And I would prefere them over Flask.
In contrast, Connexion generates Python code from API specs, requiring you to develop the API
specification first.
The choice between these approaches can depend on various factors, including project size, development team size,
and the requirement to implement external API specification.
# Run dev version (Flask werkzeug) with auto reload on source change
. ./activate.sh # build and/or activate virtual environment
make run # run dev server
# API UI
[Swagger UI](http://127.0.0.1:5000/ui)
### To authorize API calls:
- Execute from the UI API request `Users` -> `Auth` -> `Try it`
- email `admin@`, password `admin`
- press `Execute`
- copy the token from the response
- On top of the page press green button with lock icon `Authorize`
- paste in the `Value` the token
- press `Authorize` and after that `Close`
After that you can send all the API requests (`Try it out` button).
Swagger API will automatically add the security token.
# Folders overview
* `api` - Swagger (Open API) description of the API
* `src/db` - SQLAlchemy models
* `src/alembic` - DB metadata versioning
* `src/controllers` - Application logic common for Flask and Connexion
* `src/flask_server` - HTTP server (request routing to application logic)
* `src/openapi_server` - Auto-generated with `make codegen`.
`controllers/` and `encoder.py` are manually modified.
* `src/settings.py` - Configs for test/dev/prod
* `src/biuld_timestamp` - Autogenerated file with last git commit timestamp to use as 'build' time - see `make git-hook-install`
* `src/secret` - Key and certificate for signing and verification of security tokens (`jwt_token.py`)
* `src/tests` - pytests, to run use `make test`
* `src/app.py` - ASGI/WSGI app
* `src/journaling.py` - Central journaling settings
* `src/jwt_token.py` - Security tokens
* `src/password_hash.py` - Password hashing
* `src/config.py` - Config loader, is not used in this project
# Scripts
make help
# Development
## Virtual environment
Use `. ./activate.sh` to create and/or activate.
And `deactivate` to exit.
To upgrade python packages in the virtual environment use `make reqs`.
## DB
The project uses SQLAlchemy and Alembic for DB access and versioning.
To create objects in empty DB
make db-create
The DB connect string is in `src/settings.py`.
Other DB-related commands
make db-upgrade
make db-show-migration
make db-migration
## API development
To add new requests to the API, first you should implement controllers for them in `src/controllers/`.
Next we use different approaches for Flask and Connexion.
### Flask
Implement proxies for the requests in `src/flask_server/api_app.py`.
### Connexion
Add new requests to the API spec in `api/swagger.yaml`.
Run `make codegen` to generate new code in `src/openapi_server/`.
Unfortunately it can brake some manual changes - for example I had to
modify `src/openapi_server/encoder.py`. In most cases you can just rollback unwanted changes.
Next you should implement proxies for the requests in `src/openapi_server/controllers`
using signatures from autogenerated `src/openapi_server/controllers_boilerplate`.
## Libraries
* [Flask](https://flask.palletsprojects.com/en/3.0.x/)
* [Flask OpenAPI UI](https://github.com/sveint/flask-swagger-ui)
* [Connexion](https://connexion.readthedocs.io/en/latest/index.html)
* DB [SQLAlchemy](http://wiki.python.su/%D0%94%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0%D1%86%D0%B8%D0%B8/SQLAlchemy)
* [alembic](https://pypi.org/project/alembic/) for DB metadata versioning
* [flask-login](https://flask-login.readthedocs.io/en/latest/)
* [jwt](https://realpython.com/token-based-authentication-with-flask/)
## Open API (Swagger) spec
You can convert the Swagger file `api/swagger.yaml` into document at
https://editor.swagger.io or in AWS console - `Amazon AWS API Gateway`.
Visualization also available on [Swagger HUB](https://app.swaggerhub.com/apis/andgineer/api-db-prototype/1.0-oas3)
## Configs
See `settings.py`.
For `Prod` config you should specify DB in `settings.py`.
This config would be used by default (if no `SERVER_ENV` specified).
## JWT keys
For web token crypto server uses keys from files configured in the config
object.
Default is `secret/`.
Example how to recreate keys see in `create_keys.sh`.
Private key is for token issuing.
If the web application would get tokens from external service
like Amazon Cognito, you should provide only public key from that
external service, so our server could check this external service's tokens.
Public key is expected in `pem` certificate format.
## Python version
At least 3.10 because we use [Concatenate](https://peps.python.org/pep-0612/)
# Production
In production you should use production-ready servers like
Gunicorn or uWsgi.
[WSGI for Flask](https://flask.palletsprojects.com/en/3.0.x/deploying/) and
[ASGI for Connection](https://connexion.readthedocs.io/en/latest/quickstart.html#running-your-application).
See example in `prod.sh` and `Dockerfile`.
## Coverage report
* [Codecov](https://app.codecov.io/gh/andgineer/api-db-prototype/tree/master/src)
* [Coveralls](https://coveralls.io/github/andgineer/api-db-prototype)