This app provides CRUD endpoints for logistics management. Moreover, It also provides an special endpoint to check if an particular order can be fulfiled.
To run the app locally use following commands:
git clone https://github.com/sohaibfarooqi/logistik.git
virtualenv -p python3 env
source env/bin/activate
export FLASK_APP=wsgi.py
flask db migrate
flask run
At this point you will have a copy of app running locally. Access the app at http://localhost:5000/api/v1.0/order
To run test and generate coverage report use
pytest
pytest --cov=logistik tests/
To run static analyzers use:
bandit -r .
autopep8 --recursive --in-place logistik
isort **/*.py
This app contains following entities:
- Storage
- Sku
- Order
- OrderLine
These entities are linked together with following relationships
- A
Storage
can haveone-or-many
Sku
and aSku
can be inone-or-many
Storage
(Many-to-Many Relationship). - An
Order
can haveone-or-many
OrderLine
.(One-to-Many Relationship). - An
OrderLine
can have at most oneSku
and aSku
can be inone-or-many
OrderLine
(Many-to-One Relationship).
Additionally all skus in an OrderLine must be unique.
The CRUD api is implemented using a popular open source project Flask-Restless. It provides easy and elegant REST Api for SQLAlchemy models. Using this package following endpoints are exposed for all the models mentioned above
GET /<model>
GET /<model>/id
POST /<model>
PUT /<model>/id
DELETE /<model>/id
This package also support resource filtering. To get order based on customer name use following request:
order?filter[objects]=[{"name":"customer_name","op":"like","val":"Thomas"}]
Not only simple filtering, this package also supports SQL operators like and
, or
, not
etc.
Flask-Restless package also provides support for serialization and deserialization and schema checking. The schema validation is very basic level. It throws error for unknown fields and SQLAlchemy will be able to validate datatypes. Error message thrown by this package are also very naive.
All custom endpoints are inside logistik/views
directory. Currently only one endpoint i.e. order/<order_id>/fulfill
is present. This endpoint check if an order can be fulfiled using current stocks in storage. If order can be fulfiled it returns storage_id
and quantity
supplied to fulfil the order. If an order cannot be fulfiled it returns 400.
Continuous integration is setup on master branch using Travis CI
. Once the build is successful, travis send the test coverage report to Coverall
and also deploy the code to Heroku
.
This app is deployed on Heroku
platform. To access application use Base Url.
To access Swagger UI for custom enpoint use Swagger UI. To access schema endpoint for CRUD API use Schema Endpoint.
- Python 3.5
- Flask
- SQLALchemy
- PostgreSQL
- Gunicorn
- Pytest
- Swagger
- Bandit
- Autopep8
- Isort
The reason to choose above stack is as follows:
- This app is build on Flask framework. Flask is a microframework with easy to plug third party extentions on demand. This makes this framework very powerful yet lightweight.
- Datastore for this app on production is PostgreSQL. PostgreSQL is a SQL complaint database with ACID support. It also offers several extentions which comes very useful in special usecases e.g PostGIS, Unaccent, Ltree etc.
- Gunicorn is a powerful production ready container for python web apps.
- Swagger is a convenient API docs generator which is very helpful for end users to interact with.
- Bandit is a code audit library, Autopep8 is for PEP8 adherence, Isort is to organize import files.
- Add more test cases.
- Create meaningful indexes for query optimization.
- Run load test to plan capacity of system. Load testing can be done using
Apache Workbench
. - Package application using Docker.
- Add authentication support to prevent unauthorized access.
- Implement database agonistic unaccented seach. To approach this, first create a new column
which will store the
customer_name
unaccented using python packageunicodedata
. All the search will be done on this column instead of original column. There is also a PostgreSQL extentionunaccent
which can be used in this situation. But this will create dependency on PostgreSQL and this extention search with ignore case.