{"id":18725562,"url":"https://github.com/reljicd/django-rest-prod-ready-example","last_synced_at":"2026-05-09T15:05:05.193Z","repository":{"id":162023802,"uuid":"631605157","full_name":"reljicd/django-rest-prod-ready-example","owner":"reljicd","description":"Django REST API + Gunicorn + Docker + SSL + Token based authentication","archived":false,"fork":false,"pushed_at":"2023-05-05T09:50:10.000Z","size":1250,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-28T13:17:35.966Z","etag":null,"topics":["api-rest","django","django-rest-framework","gunicorn","gunicorn-web-server","python","python3","rest-api","sqlite","sqlite3","ssl","ssl-certificate"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/reljicd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-04-23T14:52:31.000Z","updated_at":"2023-05-05T09:45:30.000Z","dependencies_parsed_at":null,"dependency_job_id":"27346298-e30d-4a0f-ada6-810132694d7f","html_url":"https://github.com/reljicd/django-rest-prod-ready-example","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reljicd%2Fdjango-rest-prod-ready-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reljicd%2Fdjango-rest-prod-ready-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reljicd%2Fdjango-rest-prod-ready-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reljicd%2Fdjango-rest-prod-ready-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reljicd","download_url":"https://codeload.github.com/reljicd/django-rest-prod-ready-example/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239592980,"owners_count":19664855,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-rest","django","django-rest-framework","gunicorn","gunicorn-web-server","python","python3","rest-api","sqlite","sqlite3","ssl","ssl-certificate"],"created_at":"2024-11-07T14:10:48.041Z","updated_at":"2025-11-11T19:30:12.082Z","avatar_url":"https://github.com/reljicd.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Django REST API + Gunicorn + Docker + SSL + Token based authentication\n\n## Solution\n\n![Diagram.jpg](screenshots%2FDiagram.jpg)\n\nSolution was provided using **[Python 3.11](https://docs.python.org/3/library/index.html)**, **[Django](https://www.djangoproject.com)**, **[Django REST](https://www.django-rest-framework.org)**, **[Gunicorn](https://gunicorn.org)** and database is **SQLite**.\n\nTesting was done using Django flavor of **[untitest](https://docs.djangoproject.com/en/4.2/topics/testing/overview/)** module.\n\nSolution comes included with **[Django Admin Site](https://docs.djangoproject.com/en/4.2/ref/contrib/admin/)**. Using admin site it is possible\nto register new users and generaly to browse database and make CRUD operations on provided tables.\n\n![Screenshot 2023-04-26 at 20.16.20.png](screenshots%2FScreenshot%202023-04-26%20at%2020.16.20.png)\n![Screenshot 2023-04-26 at 20.15.51.png](screenshots%2FScreenshot%202023-04-26%20at%2020.15.51.png)\n![Screenshot 2023-04-26 at 20.17.40.png](screenshots%2FScreenshot%202023-04-26%20at%2020.17.40.png)\n\nI also provided the access to **[REST Browsable API](https://www.django-rest-framework.org/topics/browsable-api/)**. \n\n![Screenshot 2023-04-26 at 20.15.28.png](screenshots%2FScreenshot%202023-04-26%20at%2020.15.28.png)\n![Screenshot 2023-04-26 at 20.17.29.png](screenshots%2FScreenshot%202023-04-26%20at%2020.17.29.png)\n\n### Security\n\n#### Authentication\n\nAPI Authentication is provided using **[Django REST Knox](https://james1345.github.io/django-rest-knox/)** library. \n\nUser of the REST API is supposed to login using his **username** and **password** in order to obtain **token**. \nToken is then used to authenticate API endpoints.\n\nKnox provides one token per call to the login view - allowing each client to have its own token which is deleted on the server side when the client logs out. Knox also provides an optional setting to limit the amount of tokens generated per user.\n\nKnox tokens are only stored in an encrypted form. Even if the database were somehow stolen, an attacker would not be able to log in with the stolen credentials.\n\n#### SSL/TLS\n\nI generated self signed certificate and key using **OpenSSL** library for Gunicorn's SSL transport.\n\n#### Other secrets\n\n**Superuser password** and **Django secret key** are also provided as textual files that can be modified.\n\nAll the secrets are in the [secrets](secrets) folder.\n\n**_In real production these secrets would be used in CI/CD in encrypted form and services would \nuse some secret management service. They would never be passed around in plain text like this_**\n\n## URLs\n\n### Development Server: http://127.0.0.1:8080\n### Production Server: https://127.0.0.1:443\n\n### Endpoints\n\nDefined in [urls.py](src%2Fcore%2Furls.py) and [urls.py](src%2Fclicks%2Furls.py)\n\n- **/admin/** - Django Admin Site\n- **/api/clicks/campaign/:id/** - Campaign (with provided id) clicks\n- **/api/browser/** - REST Browser \n- **/api/auth/login** - Login endpoint\n- **/api/auth/logout** - Logout endpoint\n- **/api/auth/logoutall** - Invalidate all tokens endpoint\n\n## REST API\n\n### Login\n\n- **POST /api/auth/login**\n\nRequired headers\n- Authorization: Basic username:password - \n\nCredentials should be encoded using **base64**. Example in [tests.py](src%2Fclicks%2Ftests.py): \n```python\nbase64.b64encode(f'{USERNAME}:{PASSWORD}'.encode()).decode()\n```\n\n### Clicks\n\n- **GET /api/clicks/campaign/:id[int]/?after_date=:after_date[str]\u0026before_date=:before_date[str]**\n\nPath Parameters\n- **id** - campaign ID\n\nQuery Parameters\n- **after_date** - After date string in the format \"YYYY-MM-DD HH:MM:SS\"\n- **before_date** - Before date string in the format \"YYYY-MM-DD HH:MM:SS\"\n\nRequired headers\n- Authorization: Token token_value\n\nExample:\n```\nhttps://127.0.0.1/api/clicks/campaign/4510461/?after_date=2021-11-07+03:10:00\u0026before_date=2021-11-07+03:30:00\n```\n\n\n## Prerequisites for CLI and Make\n\nInstall virtual environment:\n\n```bash\n$ python -m virtualenv env\n```\n\nActivate virtual environment:\n\nOn macOS and Linux:\n```bash\n$ source env/bin/activate\n```\n\nOn Windows:\n```bash\n$ .\\env\\Scripts\\activate\n```\n\nInstall dependencies:\n```bash\n$ pip install -r requirements.txt\n```\n\n## How to run\n\n### Make\n\nThis is the easiest way to run.\n\nFor non docker commands execute [Prerequisites](#prerequisites-for-cli-and-make).\n\nAll the commands are defined in the [Makefile](Makefile).\n\n- **bootstrap** - Bootstraps Django. Includes: clean, migrate, create_superuser, import_data, collectstatic\n- **clean** - Deletes **db.sqlite3** and generated **src/static** folder.\n- **migrate** - Applies migration\n- **create_superuser** - Creates Django super user (admin)\n- **import_data** - Imports **data/click_log.csv** into **SQLite**\n- **collectstatic** - Generates static files to serve with Gunicorn and built in dev server\n- **run_tests** - Runs tests\n- **run_dev_server** - Runs development server on **http://127.0.0.1:8080**\n- **run_prod_server** - Runs Gunicorn server on **https://127.0.0.1:443**\n\n\n- **docker_build** - Builds **Docker** image\n- **docker_run_tests** - Runs tests using generated **Docker** image\n- **docker_run_dev_server** - Runs development server on **http://127.0.0.1:8080** inside **Docker** container\n- **docker_run_prod_server** - Runs Gunicorn server on **https://127.0.0.1:443** inside **Docker** container\n\nAll the commands are run from the root of the project in the form:\n```bash\n$ make command\n```\n\nExamples:\n```bash\n$ make bootstrap\n$ make run_tests\n```\n```bash\n$ make docker_run_prod_server\n```\n\n### CLI\n\nYou can run the application from the command line with **manage.py**.\n\nBefore running any command first execute [Prerequisites](#prerequisites-for-cli-and-make).\n\nFrom the root of the project:\n\nRun migrations:\n```bash\n$ python src/manage.py migrate\n```\n\nImport **data/click_log.csv** into **SQLite**:\n```bash\n$ python src/manage.py import_clicks_from_csv --path data/click_log.csv\n```\n\nCreate Django super user (admin):\n```bash\n$ python src/manage.py createsuperuser --email admin@example.com --username admin\n```\n\nGenerate static files to serve with Gunicorn and built in dev server:\n```bash\n$ python src/manage.py collectstatic\n```\n\nRun development server on port **8000**:\n```bash\n$ python src/manage.py runserver\n```\n\nRun **Gunicorn** server on port **443**, using SSL:\n```bash\n$ export DEBUG=False; export SECRET_KEY=\"${cat secrets/secret.key}\"; cd src; \\\n\tpython -m gunicorn core.wsgi \\\n\t-b :443 --keyfile ../secrets/key.pem --certfile ../secrets/cert.pem\n```\n\n### Docker\n\nIt is also possible to run servers and tests using Docker.\n\nBuild the Docker image:\n```bash\n$ docker build -t reljicd/clicks_api --build-arg DJANGO_SUPERUSER_PASSWORD=very_secret_password -f docker/Dockerfile .\n```\n\nRun development server on **http://127.0.0.1:8080** inside **Docker** container:\n```bash\n$ docker run -p 8000:8000 --rm reljicd/clicks_api manage.py runserver 0.0.0.0:8000\n```\n\nRun Gunicorn server on **https://127.0.0.1:443** inside **Docker** container:\n```bash\n$ docker run -p 443:443 -e SECRET_KEY=\"${cat secrets/secret.key}\" -e DEBUG=False --rm reljicd/clicks_api\n```\n\n## Driving REST API using Postman\n\n![Screenshot 2023-04-26 at 18.21.00.png](screenshots%2FScreenshot%202023-04-26%20at%2018.21.00.png)\n![Screenshot 2023-04-26 at 18.21.26.png](screenshots%2FScreenshot%202023-04-26%20at%2018.21.26.png)\n![Screenshot 2023-04-26 at 22.04.03.png](screenshots%2FScreenshot%202023-04-26%20at%2022.04.03.png)\n\n## Helper Tools\n\n### Django Admin\n\nIt is possible to add additional admin user who can login to the admin site. Run the following command:\n```bash\n$ python src/manage.py createsuperuser\n```\nEnter your desired username and press enter.\n```bash\nUsername: admin_username\n```\nYou will then be prompted for your desired email address:\n```bash\nEmail address: admin@example.com\n```\nThe final step is to enter your password. You will be asked to enter your password twice, the second time as a confirmation of the first.\n```bash\nPassword: **********\nPassword (again): *********\nSuperuser created successfully.\n```\n\nGo to the web browser and visit `http://127.0.0.1:8000/admin` (dev) \nor `https://127.0.0.1/admin` (prod)\n\n### REST Browsable API\n\nGo to the web browser and visit `http://127.0.0.1:8000/api/browser/` (dev)\nor `https://127.0.0.1/api/browser/` (prod)\n\n### Tests\n\nTests can be found in [tests.py](src%2Fclicks%2Ftests.py).\n\nBefore running tests using CLI or Make first execute [Prerequisites](#prerequisites-for-cli-and-make).\n\nUsing manage.py:\n```bash\n$ python src/manage.py test clicks\n```\n\nUsing make:\n```bash\n$ make run_tests\n```\n\n#### Docker\n\nIt is also possible to run tests using Docker.\nFirst build the image following instructions in [Make](#make) or [Docker](#docker)\n\nUsing docker CLI:\n```bash\n$ docker run --rm reljicd/clicks_api manage.py test clicks\n```\n\nUsing make:\n```bash\n$ make docker_run_tests\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freljicd%2Fdjango-rest-prod-ready-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freljicd%2Fdjango-rest-prod-ready-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freljicd%2Fdjango-rest-prod-ready-example/lists"}