diff --git a/.gitignore b/.gitignore index f2baf71..e581206 100644 --- a/.gitignore +++ b/.gitignore @@ -98,6 +98,7 @@ celerybeat-schedule *.sage.py # Environments +.flaskenv .env .venv env/ diff --git a/README.md b/README.md index f627b02..175ef57 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,14 @@ A sample project showing how to build a scalable, maintainable, modular Flask AP _This is an example project using the structure proposed in [this blog post](http://alanpryorjr.com/2019-05-20-flask-api-example/)._ +## Setting the environment config +Create a .flaskenv file with the following config +``` +FLASK_ENV=env|prod|test +``` -## Running the app + +## Setting the python virtual environment Preferably, first create a virtualenv and activate it, perhaps with the following command: @@ -24,14 +30,10 @@ pip install -r requirements.txt to get the dependencies. -### Manage the database -Explicitely set the environment (```dev``` ,```prod``` and ```test```) -``` -export FLASK_CONFIG=dev -``` +### Manage the database -Next, initialize the database +If first time, initialize the database ``` python manage.py seed_db @@ -42,11 +44,15 @@ Type "Y" to accept the message (which is just there to prevent you accidentally ### Run the app for local development -The following command is a shorthand for running the development server +In .flaskenv, set the `FLASK_ENV` to dev ``` -python dev.py +FLASK_ENV=dev ``` +Then, you can run the app +``` +python wsgi.py +``` ## Running tests @@ -60,7 +66,7 @@ pytest ### Deploy the app in production -##### Folder settup +##### Set the environment On the server, create the project folder @@ -78,6 +84,11 @@ Install the python packages requirements pip install -r requirements.txt ``` +In .flaskenv, set `FLASK_ENV` to prod +``` +FLASK_ENV=prod +``` + Initialize the DB (or paste an existant one) ``` python migrate.py seed_db @@ -90,4 +101,8 @@ If needed to, allow the folder access to the server user that will have control sudo chown -Rf : /var/www/flask_api_example/ ``` + + +source : https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-uswgi-and-nginx-on-ubuntu-18-04 + Navigate to the posted URL in your terminal to be greeted with Swagger, where you can test out the API. diff --git a/app/fizz/fizzbar/controller.py b/app/fizz/fizzbar/controller.py index 1c72b7e..464c03e 100644 --- a/app/fizz/fizzbar/controller.py +++ b/app/fizz/fizzbar/controller.py @@ -16,7 +16,7 @@ class FizzbarResource(Resource): """Fizzbars""" - @responds(schema=FizzbarSchema, many=True) + @responds(schema=FizzbarSchema(many=True) ) def get(self) -> List[Fizzbar]: """Get all Fizzbars""" diff --git a/app/fizz/fizzbar/interface.py b/app/fizz/fizzbar/interface.py index 903e6be..6b64ec1 100644 --- a/app/fizz/fizzbar/interface.py +++ b/app/fizz/fizzbar/interface.py @@ -1,4 +1,4 @@ -from mypy_extensions import TypedDict +from typing import TypedDict class FizzbarInterface(TypedDict, total=False): diff --git a/app/fizz/fizzbaz/controller.py b/app/fizz/fizzbaz/controller.py index 472357e..c8aa6cc 100644 --- a/app/fizz/fizzbaz/controller.py +++ b/app/fizz/fizzbaz/controller.py @@ -16,7 +16,7 @@ class FizzbazResource(Resource): """Fizzbaz""" - @responds(schema=FizzbazSchema, many=True) + @responds(schema=FizzbazSchema(many=True)) def get(self) -> List[Fizzbaz]: """Get all Fizzbaz""" diff --git a/app/fizz/fizzbaz/interface.py b/app/fizz/fizzbaz/interface.py index 751d698..b79050d 100644 --- a/app/fizz/fizzbaz/interface.py +++ b/app/fizz/fizzbaz/interface.py @@ -1,4 +1,4 @@ -from mypy_extensions import TypedDict +from typing import TypedDict class FizzbazInterface(TypedDict, total=False): diff --git a/app/other_api/doodad/controller.py b/app/other_api/doodad/controller.py index c5284da..137646b 100644 --- a/app/other_api/doodad/controller.py +++ b/app/other_api/doodad/controller.py @@ -16,7 +16,7 @@ class DoodadResource(Resource): """Doodads""" - @responds(schema=DoodadSchema, many=True) + @responds(schema=DoodadSchema(many=True)) def get(self) -> List[Doodad]: """Get all Doodads""" diff --git a/app/other_api/doodad/interface.py b/app/other_api/doodad/interface.py index 7796d2b..4f54e73 100644 --- a/app/other_api/doodad/interface.py +++ b/app/other_api/doodad/interface.py @@ -1,4 +1,4 @@ -from mypy_extensions import TypedDict +from typing import TypedDict class DoodadInterface(TypedDict, total=False): diff --git a/app/other_api/whatsit/controller.py b/app/other_api/whatsit/controller.py index 5190803..bd54049 100644 --- a/app/other_api/whatsit/controller.py +++ b/app/other_api/whatsit/controller.py @@ -16,7 +16,7 @@ class WhatsitResource(Resource): '''Whatsits''' - @responds(schema=WhatsitSchema, many=True) + @responds(schema=WhatsitSchema(many=True)) def get(self) -> List[Whatsit]: '''Get all Whatsits''' diff --git a/app/other_api/whatsit/interface.py b/app/other_api/whatsit/interface.py index 7ca2ad6..eee8bb7 100644 --- a/app/other_api/whatsit/interface.py +++ b/app/other_api/whatsit/interface.py @@ -1,4 +1,4 @@ -from mypy_extensions import TypedDict +from typing import TypedDict class WhatsitInterface(TypedDict, total=False): diff --git a/app/widget/controller.py b/app/widget/controller.py index 5d0478d..b847460 100644 --- a/app/widget/controller.py +++ b/app/widget/controller.py @@ -16,7 +16,7 @@ class WidgetResource(Resource): """Widgets""" - @responds(schema=WidgetSchema, many=True) + @responds(schema=WidgetSchema(many=True)) def get(self) -> List[Widget]: """Get all Widgets""" diff --git a/app/widget/interface.py b/app/widget/interface.py index 6c214bd..659276e 100644 --- a/app/widget/interface.py +++ b/app/widget/interface.py @@ -1,4 +1,4 @@ -from mypy_extensions import TypedDict +from typing import TypedDict class WidgetInterface(TypedDict, total=False): diff --git a/config.ini b/config.ini index 72c5cea..fd17c54 100644 --- a/config.ini +++ b/config.ini @@ -8,4 +8,6 @@ socket = flask_api_example.sock chmod-socket = 660 vacuum = true -die-on-term = true \ No newline at end of file +die-on-term = true + +/var/www/flask_api_example \ No newline at end of file diff --git a/dev.py b/dev.py deleted file mode 100644 index c0ba918..0000000 --- a/dev.py +++ /dev/null @@ -1,5 +0,0 @@ -from app import create_app - -app = create_app("dev") -if __name__ == "__main__": - app.run(debug=True) \ No newline at end of file diff --git a/manage.py b/manage.py index 17b8003..8ca5113 100644 --- a/manage.py +++ b/manage.py @@ -4,7 +4,10 @@ from app import create_app, db from commands.seed_command import SeedCommand -env = os.getenv("FLASK_CONFIG") or "test" +from dotenv import load_dotenv +load_dotenv(dotenv_path=".flaskenv", verbose=True) + +env = os.getenv("FLASK_ENV") or "test" print(f"Active environment: * {env} *") app = create_app(env) diff --git a/requirements.txt b/requirements.txt index 7c221fd..2e8fa8f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,22 +1,21 @@ -aniso8601==7.0.0 -attrs==19.1.0 +aniso8601==8.0.0 +attrs==20.2.0 cffi==1.14.3 -Click==7.0 +click==7.1.2 cryptography==3.1.1 -Flask==1.1.1 -flask-accepts==0.10.0 -Flask-RESTful==0.3.7 -flask-restplus==0.12.1 -flask-restx==0.1.0 +Flask==1.1.2 +flask-accepts==0.17.4 +Flask-RESTful==0.3.8 +flask-restplus==0.13.0 +flask-restx==0.2.0 Flask-Script==2.0.6 -Flask-SQLAlchemy==2.4.0 +Flask-SQLAlchemy==2.4.4 iniconfig==1.1.1 itsdangerous==1.1.0 -Jinja2==2.10.1 -jsonschema==3.0.2 +Jinja2==2.11.2 +jsonschema==3.2.0 MarkupSafe==1.1.1 -marshmallow==3.2.0 -mypy-extensions==0.4.1 +marshmallow==3.8.0 numpy==1.19.2 packaging==20.4 pandas==1.1.3 @@ -24,11 +23,13 @@ pluggy==0.13.1 py==1.9.0 pycparser==2.20 pyparsing==2.4.7 -pyrsistent==0.15.4 +pyrsistent==0.17.3 pytest==6.1.1 -python-dateutil==2.8.0 -pytz==2019.2 -six==1.12.0 -SQLAlchemy==1.3.6 +python-dateutil==2.8.1 +python-dotenv==0.14.0 +pytz==2020.1 +six==1.15.0 +SQLAlchemy==1.3.20 toml==0.10.1 -Werkzeug==0.15.5 +uWSGI==2.0.19.1 +Werkzeug==1.0.1 diff --git a/wsgi.py b/wsgi.py index 2a4134c..63fc433 100644 --- a/wsgi.py +++ b/wsgi.py @@ -2,6 +2,6 @@ from app import create_app -app = create_app(os.getenv("FLASK_CONFIG") or "test") +app = create_app(os.getenv("FLASK_ENV") or "test") if __name__ == "__main__": app.run(debug=True)