A minimal REST api written using django framework. This api uses django-rest-framework in REST api layer and uses postgresql in database layer. The project structure of this api resembles that of n-tier architecture and it was preferred over MVT architecture of django because of better abstraction of business logic from model layer(orm).
This api has a very minimal authentication/authorization functionality just to make sure two users can only be able to modify their own data. Rest of the functionality such as adding/removing books and authors are right now handled using django admin panel.
- Database: This project uses postgresql database which is accessed using django object relational mapper.
base_app/models.py: Makes up the data access object of n-tier. Where django models only contains fields present in repective table of relational database. Each django model is accompanied by a model manager which only handles CRUD operations on its model using quersets.rest_api/services.py: Makes up the services layer of n-tier. This file does not contains any classes, only functions. The functions present in this module are together reponsible for cross communication of data between all the django models present in this api.rest_api/views.py: Makes up the RESTful api layer of n-tier. This api provides GET, POST and PUT endpoints.
.
└── owl_library
├── owl_library # [dir] main django project
| └── ...
├── base_app # [dir] main application
| └── models.py # data access object layer / orm
│ └── tests # [dir] contains all app level test files
│ └── test_models.py # unit testing models
| └── ...
| └── ...
├── rest_api # [dir] django-rest-framework based module
| └── services.py # business logic (connects api and dao layers)
│ └── urls.py # REST api layer
│ └── views.py # REST api layer
│ └── serializers.py # [de]serialize model object [from]to response object
│ └── tests # [dir] contains all rest_api/service level test files
│ └── test_services.py # unit testing business logic
│ └── test_views.py # integration testing api endpoints
│ └── ...
├── diagrams # [dir] contains diagrams for docs
├── manage.py
└── ...
- Author: Stores
nameandis_popularattributes related to an author. There can be multiple books in the library with same author. So it holds one-to-many relationship withBook. - Book: Stores
owl_idandtitleas class attributes whileauthoras a foreign key attribute.owl_idis the identifies which uniquely identifies a book in the library. Right now a book is constrainted to have only one author. Another important property ofBookmodel is that, there can't be more than one book with same combination oftitleandauthor, represented by unique constraint. - BookCopy: The main purpose of this model is to handle the removal of unique constraint present in
book_title-authorattributes ofBookmodel, i.e. in case future requirements allow library to keep multiple copies of a book represented by sameowl_idthen those copies can easily be represented byBookCopymodel. The only attribute of this model isbook_copy_type. It's kept here instead inBookmodel because it seems more related toBookCopy. It also goes hand-in-hand with the extension of library to keep multiple copies of several more types likesoft-copy. - LibraryUser: This class extends
AbstractUserdjango auth model class.Usernameshall be used to identify a particular user of the owl library. Currently user registration is handled from django admin panel. - BorrowRecord: This model keeps track of all the books borrowed so far from the library. Once a record is created it is only deleted in special instances(for example when cool-down period of
LibraryUserends).
/: Denotes aGETrequest endpoint and returns list of all books present in the library as response./books/available/: Denotes aGETrequest endpoint and returns list of all available books./books/author/<name>: Denotes aGETrequest endpoint, where<name>is the author name, which is searched against all the books with similar author names present in the library. Returns list of such books as reponse./accounts/borrow/: Denotes aPOSTrequest. Requires user authentication. Allows api user to borrow a book with givenowl_idof the book. Accepts request with data payload in the format{"owl_id":"valid_uuid_of_book_present_in_library"}. Returns exception message as response object for invalid payload or other appropriate message depending upon the state of the database./accounts/return/: Denotes aPUTrequest endpoint. Requires user authentication Allows api user to return an already borrowed book. Successful request accepts data in format{"owl_id":"valid_uuid_of_already_borrowed_book"}./accounts/availability/<owl_id>: Denotes aGETendpoint. Requires user authentication. Takesowl_idas url parameter. Returns information on availability of the queries book for a given user./accounts/records/: Denotes aGETendpoints. Requires user authentication. Returns list of all borrow records assocuated for a given user. Keeps track of all books irrespective of their return status./accounts/register/: Django defaultCreateApiViewto let outside users register an account for api use.
- Popular-author: Owl library identifies some authors as popular. A
LibraryUsercan borrow books with such authors only once in every 6 months. Currently, all authors with name starting with letter 'J' are defined as popular. - Book-copy-type: There are three types of books in Owl library right now, they are
paperbacks,hardcoverandhandmade. - Cool-down-period: Once a
LibraryUserborrows a book, the same book cannot be borrowed again untilcool-down-periodis passed (given that the book is returned within due date). For books written by non-popular authorscool-down-periodis 3 months, and 6 months for books by popular authors. Note thatcool-down-periodis modelled logically usingborrow_dateattribute ofBorrowRecordmodel.
- Present project state diagram (Django AbstractUser is used as a LibraryUser model)
- Legacy diagram 1 (non-UUID primary keys)
- Legacy diagram 2 (missing requirements)
- Running docker engine
- Clone this github repo and go the directory of the project
- Open terminal and run command:
docker compose up
- Postgresql installation
- Python3
- Clone this github repo and go the directory of the project
- Create a virtual environment for the project
- Activate virtual environment
- Run
pip install -r requirements.txt - Create a
.envfile in parent directory of github project directory - Put following contents in your
.envfile (update fields according to your psql configuration)
DATABASE_NAME=existing_psql_database_name
DATABASE_USER=your_psql_username
DATABASE_PASS=your_psql_password - Run
python manage.py runserverand open the server link in your browser - Go to this url
http://127.0.0.1:8000/accounts/register/to register a new user account by entering username and password - Go back to root url and click on
Loginbutton present in top-right corner - Enter username and password
- Start browsing the api
These steps assume that you have followed steps to use browsable api
- Stop the server
- Goal here is to run a script present in this path
dummy_data/insert_dummy_data_1.py.
2.1. Windows users can do that by executing this command after opening up the django python shell. At first runpython manage.py shelland then execute the commandexec(open('dummy_data\insert_dummy_data_1.py').read())
2.2. Linux users can use this commandpython manage.py shell < ./dummy_data/insert_dummy_data_1.py
This project uses django wrapper of python unittest for unit testing, unittest.mock for mocking and rest_framwork APITestCase for integration testing. To run unit all unit and integration test run python manage.py test.
Django-rest-framework docs
Django docs
Django Web Framework (Python) tutorial
Where to put business logic in Django?
Django REST Framework Oversimplified
Django Rest Framework | Serializers & CRUD
Django REST Framework - Build an API from Scratch


