Bakers-kiss is an API service for bakers to be able to manage their orders, store recipes (in order to avoid deterioration in case the recipe is primarily written on paper), keep their recipes secure and get notifications via email reminding them to stock up. This project is a Webstack: Portfolio Project, signaling the last phase of ALX SWE training, under the short specialisation. The project is aimed to showcase what the student can do having come so far into the program.
The API service helps bakers to manage their activities like keep track of their orders and not forget due dates, store recipes for safe keeping (either by theft or deteriotation of the paper it was written on), and get reminder to stock up their ingredients.
- Python programming language for its simplicity.
- Flask for building the backend web application in Python. This was chosen since Flask is a light-weight and flexible micro-framework.
- Flask-SQLALchemy for easy interaction with the database.
- Flask-JWT for implementing authentication and authorization mechanisms which allows users to authenticate and access protected endpoints securely.
- Flask-RESTX for documenting the API endpoints. Flask-RESTX makes it easier to automatically generate interactive API documentation from code annotations (using Swagger).
- SQLite / MySQL for database.
- Python virtual environment for managing dependencies used during the project development.
- Git for version control, Github for hosting the repository.
- sqlite for testing without having to use a complicated database during development stage.
- Insomnia for API mocking (debugging and testing).
- Ethereal.email to generate dummy email accounts.
NOTE: This was done on linux
- Clone or fork this repo
$ git clone https://github.com/keme-ebi/Bakers-kiss.git
- Setup python virtual environment in the Bakers-kiss folder.
:~/Bakers-kiss$ python3 -m venv {name of virtual environment}
- example:
$ python3 -m venv env
- Activate virtual environment
:~/Bakers-kiss$ source env/bin/activate
- To deactivate virtual environment
(env) :~/Bakers-kiss$ deactivate
- Install dependencies
(env) :~/Bakers-kiss$ pip install -r requirements.txt
Environment for the project is setup.
After activation of virtual environment run:
(env) :~/Bakers-kiss$ export FLASK_APP=app/
Then open flask shell: (env) :~/Bakers-kiss$ flask shell
If you're using MySQL (Make sure MySQL is running in the background first) to run the program, edit the file create_db.py and put your credentials, then run it to create the database for the project. If you're using SQLite, skip this:
(env) :~/Bakers-kiss$ python create_db.py
Create the database in the shell and exit the shell:
>>> db.create_all()
After installation, run the server
(env) :~/Bakers-kiss$ python server.py
Open another terminal and access the endpoints or test it directly in your browser by using localhost:5000
This is a table of the API endpoints and their uses. The endpoints are used to access various routes provided after server has started runnning. Can be mocked using Postman or Insomnia according to your preferred choice.
NOTE: localhost is used in place of actual url, for testing/development purposes
URL | HTTP METHOD | USE |
---|---|---|
localhost:5000/signup | POST | signs a new user up / registers a new user |
localhost:5000/login | POST | logins in a registered user |
localhost:5000/orders | GET | gets all orders of an authorized user |
localhost:5000/orders | POST | puts or inserts a new order |
localhost:5000/orders/<int:order_id> | GET | gets a specific order of an authorized user by its order id |
localhost:5000/orders/<int:order_id> | PUT | updates a specific order of an authorized user by its order id |
localhost:5000/orders/<int:order_id> | DELETE | deletes a specific order of an authorized user by its order id |
localhost:5000/recipes | GET | gets all recipes of an authorized user |
localhost:5000/recipes | POST | inserts new recipes for an authorized user |
localhost:5000/recipes/<int:recipe_id> | GET | gets a specific recipe of an authorized user by its reciped id |
localhost:5000/recipes/<int:recipe_id> | PUT | updates the data of a specific recipe of an authorized user by its recipe id |
localhost:5000/recipes/<int:recipe_id> | DELETE | deletes a specific recipe of an authorized user by its recipe id |
NOTE: Each routes except the signup and login, are jwt_required, so a token is needed to access other routes, this will ensure that a user is authorized.
NOTE: Some actions sends a mail to user, so ensure you put a valid mail for testing purpose. You can create a fake/dummy mail from ethereal.email
$ curl -X 'POST' 'http://localhost:5000/auth/signup' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{"username": "Nonso", "email": "testa@email.com", "password": "password"}'
$ curl -X 'POST' 'http://localhost:5000/auth/login' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{"email": "test@email.com", "password": "password"}'
$ curl -X 'POST' 'http://localhost:5000/orders/' -H 'accept: application/json' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcxNzM3MDIxNiwianRpIjoiMTc0MmVjZGEtMTE3OS00NjY0LTliMGEtMGIxNDUwYjk5YjllIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImthcmlhIiwibmJmIjoxNzE3MzcwMjE2LCJjc3JmIjoiZTIxZTkyYzMtY2FlZi00N2FlLTk0ZjItNTIyODA4NTgxMzJhIiwiZXhwIjoxNzE3MzcyMDE2fQ.P3KIZoFTKdEDMezHQQjlsVxZUKMew1BUqG66e-QTYAI' -H 'Content-Type: application/json' -d '{"client": "Tochi", "order_title": "birthday cake", "description": "1 layer red velvet, black whipped cream", "price": 30.49, "due_date": "2024-06-07"}'
$ curl -X 'GET' 'http://localhost:5000/orders/' -H 'accept: application/json' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcxNzM3MDIxNiwianRpIjoiMTc0MmVjZGEtMTE3OS00NjY0LTliMGEtMGIxNDUwYjk5YjllIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImthcmlhIiwibmJmIjoxNzE3MzcwMjE2LCJjc3JmIjoiZTIxZTkyYzMtY2FlZi00N2FlLTk0ZjItNTIyODA4NTgxMzJhIiwiZXhwIjoxNzE3MzcyMDE2fQ.P3KIZoFTKdEDMezHQQjlsVxZUKMew1BUqG66e-QTYAI'
$ curl -X 'GET' 'http://localhost:5000/orders/1' -H 'accept: application/json' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcxNzM3MDIxNiwianRpIjoiMTc0MmVjZGEtMTE3OS00NjY0LTliMGEtMGIxNDUwYjk5YjllIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImthcmlhIiwibmJmIjoxNzE3MzcwMjE2LCJjc3JmIjoiZTIxZTkyYzMtY2FlZi00N2FlLTk0ZjItNTIyODA4NTgxMzJhIiwiZXhwIjoxNzE3MzcyMDE2fQ.P3KIZoFTKdEDMezHQQjlsVxZUKMew1BUqG66e-QTYAI'
$ curl -X 'PUT' 'http://localhost:5000/orders/1' -H 'accept: application/json' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcxNzM3MDIxNiwianRpIjoiMTc0MmVjZGEtMTE3OS00NjY0LTliMGEtMGIxNDUwYjk5YjllIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImthcmlhIiwibmJmIjoxNzE3MzcwMjE2LCJjc3JmIjoiZTIxZTkyYzMtY2FlZi00N2FlLTk0ZjItNTIyODA4NTgxMzJhIiwiZXhwIjoxNzE3MzcyMDE2fQ.P3KIZoFTKdEDMezHQQjlsVxZUKMew1BUqG66e-QTYAI' -H 'Content-Type: application/json' -d '{"client": "Joel"}'
$ curl -X 'DELETE' 'http://localhost:5000/orders/1' -H 'accept: application/json' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcxNzM3MDIxNiwianRpIjoiMTc0MmVjZGEtMTE3OS00NjY0LTliMGEtMGIxNDUwYjk5YjllIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImthcmlhIiwibmJmIjoxNzE3MzcwMjE2LCJjc3JmIjoiZTIxZTkyYzMtY2FlZi00N2FlLTk0ZjItNTIyODA4NTgxMzJhIiwiZXhwIjoxNzE3MzcyMDE2fQ.P3KIZoFTKdEDMezHQQjlsVxZUKMew1BUqG66e-QTYAI'
$ curl -X 'POST' 'http://localhost:5000/recipes/' -H 'accept: application/json' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcxNzM3MDIxNiwianRpIjoiMTc0MmVjZGEtMTE3OS00NjY0LTliMGEtMGIxNDUwYjk5YjllIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImthcmlhIiwibmJmIjoxNzE3MzcwMjE2LCJjc3JmIjoiZTIxZTkyYzMtY2FlZi00N2FlLTk0ZjItNTIyODA4NTgxMzJhIiwiZXhwIjoxNzE3MzcyMDE2fQ.P3KIZoFTKdEDMezHQQjlsVxZUKMew1BUqG66e-QTYAI' -H 'Content-Type: application/json' -d '{"pastry_name": "sponge cake", "ingredients": "2 cups of..." "recipe": "add flour to..."}'
$ curl -X 'GET' 'http://localhost:5000/recipes/' -H 'accept: application/json' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcxNzM3MDIxNiwianRpIjoiMTc0MmVjZGEtMTE3OS00NjY0LTliMGEtMGIxNDUwYjk5YjllIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImthcmlhIiwibmJmIjoxNzE3MzcwMjE2LCJjc3JmIjoiZTIxZTkyYzMtY2FlZi00N2FlLTk0ZjItNTIyODA4NTgxMzJhIiwiZXhwIjoxNzE3MzcyMDE2fQ.P3KIZoFTKdEDMezHQQjlsVxZUKMew1BUqG66e-QTYAI'
$ curl -X 'GET' 'http://localhost:5000/recipes/1' -H 'accept: application/json' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcxNzM3MDIxNiwianRpIjoiMTc0MmVjZGEtMTE3OS00NjY0LTliMGEtMGIxNDUwYjk5YjllIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImthcmlhIiwibmJmIjoxNzE3MzcwMjE2LCJjc3JmIjoiZTIxZTkyYzMtY2FlZi00N2FlLTk0ZjItNTIyODA4NTgxMzJhIiwiZXhwIjoxNzE3MzcyMDE2fQ.P3KIZoFTKdEDMezHQQjlsVxZUKMew1BUqG66e-QTYAI'
$ curl -X 'PUT' 'http://localhost:5000/recipes/1' -H 'accept: application/json' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcxNzM3MDIxNiwianRpIjoiMTc0MmVjZGEtMTE3OS00NjY0LTliMGEtMGIxNDUwYjk5YjllIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImthcmlhIiwibmJmIjoxNzE3MzcwMjE2LCJjc3JmIjoiZTIxZTkyYzMtY2FlZi00N2FlLTk0ZjItNTIyODA4NTgxMzJhIiwiZXhwIjoxNzE3MzcyMDE2fQ.P3KIZoFTKdEDMezHQQjlsVxZUKMew1BUqG66e-QTYAI' -H 'Content-Type: application/json' -d '{"pastry_name": "super sponge cake"}'
$ curl -X 'DELETE' 'http://localhost:5000/recipes/1' -H 'accept: application/json' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcxNzM3MDIxNiwianRpIjoiMTc0MmVjZGEtMTE3OS00NjY0LTliMGEtMGIxNDUwYjk5YjllIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImthcmlhIiwibmJmIjoxNzE3MzcwMjE2LCJjc3JmIjoiZTIxZTkyYzMtY2FlZi00N2FlLTk0ZjItNTIyODA4NTgxMzJhIiwiZXhwIjoxNzE3MzcyMDE2fQ.P3KIZoFTKdEDMezHQQjlsVxZUKMew1BUqG66e-QTYAI'
After playing around with it, you can terminate via the 1st terminal using ctrl C