Skip to content

🎴 Images API with expiring thumbnails and user tiers.

Notifications You must be signed in to change notification settings

BSski/django-images-api

Repository files navigation

Django Images API

Build Status Maintainability CodeFactor Code style: black

🎆 Live demo 🎆

[Heroku retracted its free tier, therefore all my demos are unavailable until further notice.]

Table of contents

📜 Project description

This is a recruitment task for a Junior Python Developer position.

The project:

  • is an Images API,
  • where users can list their images,
  • with 3 main built-in user tiers (Basic, Premium, Enterprise) with varying permissions to:
    • fetch a link to a permitted thumbnail size,
    • fetch an expiring link to a permitted thumbnail size (300-30000 sec),
    • fetch a link to the original image,
  • where user tiers with arbitrary permissions can be created via admin panel,
  • and if a user tier settings change, all its users are updated, and so are their images,
  • and if a user's user tier changes, his images get updated,
  • and if an image's owner changed, its thumbnail links are updated,
  • user inputted data is validated (includes regex!),
  • project's design and architecture was created with performance in mind:
    • only original user's images are stored permanently: thumbnails are stored in a S3 bucket which deletes files that were not accessed for 7 days,
    • thumbnail is generated only when requested, by AWS Lambda function,
    • JWT token is used for authentication to minimize number of connection to the database,
  • many throttling mechanisms were added,
  • pagination was added,
  • HyperlinkedRelatedField for user's info in images list view was added,
  • the code has docstrings,
  • and it's easily deployable via docker (you need your own AWS architecture),
  • there is a CI/CD pipeline which runs tests, black linter check, dockerizes the project and deploys it to Heroku from the Docker container,
  • there are authentication and authorization mechanisms: user's JWT token is saved as cookie, but it can also be passed in requests as a bearer token.

🔨 Technologies used

  • Python 3.7 & 3.8
  • Django 3.2
  • Django REST Framework
  • PostgreSQL 14.2
  • AWS S3
  • AWS Lambda
  • Gunicorn
  • Docker
  • SemaphoreCI
  • Heroku
  • dj-rest-auth with JWT Token

🛠️ Deployment

A) through Docker:

  1. Create an .env file basing on .env_sample_file from the repository. Set PORT to 8020.

  2. Run docker run --env-file .env -p 8020:8020 bsski/images-api:latest in the .env file directory.

  3. Access localhost:8020.

B) without Docker:

  1. Download the repository.

  2. Create a virtual environment.

  3. Run pip install -r requirements.txt (or requirements-windows.txt) in the directory of requirements.txt.

  4. Create an .env file basing on .env_sample_file from the repository in the directory of .env_sample_file. Set PORT to 8000.

  5. Run python manage.py runserver in the directory of manage.py.

  6. Access 127.0.0.1:8000.

The admin panel can be found under your chosen URL or, if you didn't set it in the .env file, the default /hidden_admin_url.

Security through obscurity is not enough of course, but I find it a nice complementary solution.

🔐 Environment variables

To run this project, you have to set up the following environment variables in the .env file (the values below are exemplary):

SECRET_KEY=TestSecretKey
AWS_S3_REGION_NAME=eu-central-1
AWS_S3_ADDRESSING_STYLE=virtal
AWS_S3_SIGNATURE_VERSION=s3v4
AWS_ACCESS_KEY_ID=MFAA21AFHG9AFKA2AEY
AWS_SECRET_ACCESS_KEY=13Fjm32eam23k23Qf432fDFda9saf
AWS_STORAGE_BUCKET_NAME=main-bucket
AWS_THUMBNAILS_STORAGE_BUCKET_NAME=thumbnails-bucket
DEFAULT_FILE_STORAGE=storages.backends.s3boto3.S3Boto3Storage
PORT=8020
ADMIN_LOGIN_URL=test_admin_login_url
DJANGO_SUPERUSER_PASSWORD=TestAdminPassword
DJANGO_SUPERUSER_USERNAME=TestAdminName
DJANGO_SUPERUSER_EMAIL=TestAdmin@email.com
LOCALSTACK_ENDPOINT_URL=http://localhost:4566

🚀 Main features

The recruitment task demanded such features and all are provided in a required format:

  • sending a POST request to /auth/login/ lets you log in,
  • sending a POST request to /auth/logout/ lets you log out,
  • accessing /images/images/ when logged in lists current user's images,
  • accessing 'images/images/' when logged in with ?limit=3 at the end of it sets a pagination for the current page,
  • accessing thumbnail link from image view with ?time_exp=500 at the end of it generates a link to it expiring in 500 seconds (if logged in user is permitted to do that; range: 300-30000).

Furthermore, the website is deployed on Heroku from a Docker image using a CI/CD SemaphoreCI pipeline:

CI/CD screenshot

⬆️ Room for improvement

Due to the time limitation, there are very important things left to add:

  • Localstack to test and run app locally,
  • tests,
  • typehints,
  • global AWS clients instead of temporary ones,
  • the code would also benefit from some cleaning,
  • logging.

👷 Author