Home
Softono
url-shortener-django-modern-rest-example

url-shortener-django-modern-rest-example

Open source MIT Python
11
Stars
1
Forks
0
Issues
1
Watchers
1 month
Last Commit

About url-shortener-django-modern-rest-example

Simple URL Shortener implemention powered by django modern rest

Platforms

Web Self-hosted

Languages

Python

Links

URL Shortener — django-modern-rest example

Python Django django-modern-rest Pydantic uv Ruff mypy Coverage License: MIT

REST API example built with Django and django-modern-rest, following the architectural conventions of wemake-django-template.

The service accepts a long URL and returns a short code. Visiting the short code redirects to the original URL and increments the click counter.

Special thanks to @sobolevn and @kondratevdev


Stack

Layer Tools
Language Python 3.13
Framework Django 6 + django-modern-rest
Schemas / validation Pydantic v2
Database SQLite (via Django ORM)
Server Gunicorn (prod) / runserver (dev)
Package manager uv
Linter / formatter ruff
Type checking mypy (strict) + django-stubs
Tests pytest + pytest-django + schemathesis
Containerisation Docker + Docker Compose (dev / prod)

Project structure

dmr-urlshortener-example/
│
├── manage.py
├── pyproject.toml          # dependencies, mypy, ruff, pytest config
├── Makefile                # all commands in one place
├── Dockerfile
├── docker-compose.yml          # production
├── docker-compose.override.yml # dev (applied automatically)
│
├── config/                 # Django configuration
│   ├── settings.py
│   ├── urls.py
│   ├── asgi.py
│   └── wsgi.py
│
├── apps/
│   └── urlshortener/
│       │
│       ├── api/            # HTTP layer (dmr)
│       │   ├── controllers.py  # Controller classes (POST /links, GET /{code})
│       │   ├── schemas.py      # Pydantic request / response schemas
│       │   ├── mappers.py      # Entity → Response DTO
│       │   └── routers.py      # route registration
│       │
│       ├── domain/         # business logic (no Django dependencies)
│       │   ├── models.py       # ShortLinkEntity (dataclass)
│       │   ├── services.py     # use cases + short-code generation services
│       │   ├── interfaces.py   # Protocol interfaces
│       │   └── constants.py
│       │
│       ├── infrastructure/ # database layer
│       │   ├── models.py       # Django ORM models
│       │   ├── repositories.py # repository implementation
│       │   └── mappers.py      # ORM model ↔ Entity
│       │
│       ├── migrations/     # standard Django migrations
│       ├── factories.py    # dependency factories (DI)
│       ├── admin.py
│       └── apps.py
│
├── common/                 # shared utilities across apps
│
└── tests/
    ├── conftest.py
    ├── plugins/
    │   └── django_settings.py
    └── test_apps/
        └── test_urlshortener/
            ├── test_api.py     # HTTP integration tests
            ├── test_domain.py  # business logic unit tests
            ├── test_models.py
            └── test_schema.py

Architecture layers

HTTP request
    │
    ▼
┌─────────────────────────────────┐
│  api/  (controllers, schemas)   │  ← HTTP only: parsing, serialisation
└─────────────────┬───────────────┘
                  │ calls use case
                  ▼
┌─────────────────────────────────┐
│  domain/  (services, models)    │  ← business rules, no Django imports
└─────────────────┬───────────────┘
                  │ via Protocol interface
                  ▼
┌─────────────────────────────────┐
│  infrastructure/ (repositories) │  ← ORM, SQL, external services
└─────────────────────────────────┘

Quick start

Local (without Docker)

Requirements: Python 3.13, uv

# 1. Clone and enter the directory
git clone <repo-url> && cd dmr-urlshortener-example

# 2. Install dependencies
make install-dev

# 3. Apply migrations
make migrate

# 4. Run the development server
make run

The service is available at http://localhost:8000. OpenAPI schema — http://localhost:8000/docs/openapi.json/.


Docker (recommended)

Requirements: Docker, Docker Compose

# Development mode (hot-reload, dev dependencies inside the container)
make run-docker

# Production mode (gunicorn, no dev dependencies)
DJANGO_SECRET_KEY=<secret> make run-prod

Both modes run migrate automatically on startup.


Example requests

# Create a short link
curl -X POST http://localhost:8000/links/ \
  -H "Content-Type: application/json" \
  -d '{"original_url": "https://example.com/very/long/path"}'

# Response:
# {"short_code": "aB3xZ9", "original_url": "https://example.com/very/long/path", "clicks": 0}

# Follow a short link (returns 302 → original_url)
curl -L http://localhost:8000/aB3xZ9/

Development commands

make help           # list all available commands

make test           # run full test suite with coverage
make test-fast      # run tests without coverage (faster feedback)
make lint           # ruff check without auto-fix
make format         # auto-format with ruff
make typecheck      # strict mypy check
make check          # lint + typecheck + test in one command

make migrate        # apply migrations locally
make makemigrations # create new migrations
make shell          # open Django shell

Links