A stepping stone codebase to working on "The Unicorn Project". (1, 2)
- Python3.7 or higher
- SQLite
Python3.7 is the lowest supported version due to heavy usage of Python 3.7's dataclasses feature to improve code readability and self-documentation of data structures. If back porting was a requirement, they could be refactored out to use the NamedTuple class or namedtuple collection objects instead. Use of a 3rd party library such as attrs is also an alternative.
-
Clone the code.
git clone https://github.com/DavidWalshe93/The_Phoenix_Project.git
-
Navigate to the root directory of the project:
cd <PATH_TO_DIR>/The_Phoenix_Project/
-
Create a virtual environment
python3 -m venv venv
-
Activate the virtual environment
source ./venv/bin/activate
-
Install requirements
pip install -r requirements.txt
-
Setup ENV Variables
# Sources Flask application ENV variables. source dev_setup.sh # Key used for password hashing. export SECRET_KEY="abc" # Key used for registering as an ADMIN. export ADMIN_SECRET_KEY="XYZ"
-
Run Tests
pytest
-
Run Dev Server
flask run
- Create, Update, Delete and List web service endpoints for a User object.
- User object should contain a name, email address, password and the date of their last login.
- Provide a login endpoint that validates the email address and password provided by the user matches the one stored in the database
Below are some thoughts behind why the application stack was chosen.
Component | Framework/Library | Why |
---|---|---|
Python | -- | Most experience with. |
API | Flask/FlaskRESTful | Rapid prototyping with large eco-system of feature plugins. |
Database | SQLite | Good for prototyping and fast dev-test cycle with in-memory functionality, ideal for repeatable unit/functional testing. |
ORM | SQLAlchemy | Easier to work with and faster turn around time than writing raw SQL. Better code readability. |
DTO/Schema | Marshmallow | Easy transfer of database objects/Request bodies into various data-structures including Dicts/Dataclasses/Namespaces. |
Login/Role Management | FlaskHTTPAuth | Supplies a simple role based system out-of-the-box, protects endpoints using the intuitive decorator pattern. |
Token Access | FlaskHTTPAuth/itsdangerous | Allows both Bearer Token and Basic Authentication. |
Password Hashing | Werkzeug | Clear interface for hashing passwords before saving to database and for verifying hashed passwords on login attempts. |
Below are the endpoints for the given application.
Endpoint | Method | Auth | Action |
---|---|---|---|
/api/v1/register | POST | ๐ด | Registers a new user/admin with the system. |
/api/v1/login | POST | ๐ด | Login an existing user. |
/api/v1/users | GET | ๐ต | List all user's usernames and last login timestamp. |
/api/v1/users/me | GET | ๐ต | Get the current user's information. (email, username, last login) |
/api/v1/users/me | PUT | ๐ต | Update the current user's username and/or password. |
/api/v1/users/me | DELETE | ๐ต | Close the current user's account. |
/api/v1/users/<:id> | GET | ๐ต | Get a single user's id, username and last login from their ID. |
/api/v1/users/<:id> | GET | ๐ข | Get a single user's id, username, email, role and last login, given their ID. |
/api/v1/users/<:id> | PUT | ๐ข | Update a single user's username and/or password based on their ID. |
/api/v1/users/<:id> | DELETE | ๐ข | Delete a single user based on their ID. |
/api/v1/users | GET | ๐ข | Get all user's usernames, emails and last login timestamps. |
/api/v1/users | DELETE | ๐ข | Delete a group of users based on a list of ID's |
Role | Access Level | Description |
---|---|---|
Anonyomous | ๐ด | Non-logged in user. |
User | ๐ต | Logged in user with User privileges. |
Admin | ๐ข | Logged in user with Admin privileges. |
Testing was carried out using the PyTest framework with 43 tests created in total.
Pytest was chosen over unittest/nosetest for its expressive syntax and powerful fixture injection features, greatly reducing boilerplate code.
The image below depicts the granular coverage report for the delivered application.
Postman was also used to test against a development instance of the application during development. The exported Postman project can be found in the ./postman directory.
To improve repeatability, two helper requests were setup to clear the development application's database and then initialise it with five users before running the rest of the request tests. This allowed requests to start from the same state each test cycle.
The tests were written using Postman's Test API and the Pre/Post request hooks offered by Postman.
A simple CI/CD flow is created to showcase understanding of core DevOps fundamentals and to keep code honest outside the original development environment.
Component | Service | Links |
---|---|---|
SCM | GitHub | |
Build Agent | Travis CI | |
Coverage Analysis | Coveralls | |
Code Quality Analysis | Codacy |
Due to timing constraints, some aspects of the project were not fully realised, this section is supplied to highlight where additional time would have been spent.
-
โ Continue to improve test coverage.
- Add tox to check against multiple versions of Python.
- Add additional unittesting to validate rarely activated code paths.
-
โ Add additional endpoint, allowing admins to create a User.
-
โ Add Docker support for better test/deployment support.
- โ๏ธSemi-realised by Travis CI, which builds a docker container to run tests on, ensuring no hidden dependencies are on local machine
-
โ Deploy to PaaS provider such as Digital Ocean or Heroku or a CSP such as AWS or Azure.