DEV Community

Alex Spinov
Alex Spinov

Posted on

Django Ninja Has a Free API — FastAPI-Style Endpoints in Django

Django Ninja brings FastAPI-style API development to Django. Type hints, automatic validation, OpenAPI docs — all running on Django's battle-tested ORM and middleware.

Why Django Ninja?

FastAPI is great but doesn't have Django's ORM, admin, auth, or migrations. Django REST Framework is powerful but verbose. Django Ninja gives you the best of both worlds.

Quick Start

pip install django-ninja
Enter fullscreen mode Exit fullscreen mode
# api.py
from ninja import NinjaAPI

api = NinjaAPI()

@api.get('/hello')
def hello(request, name: str = 'World'):
    return {'message': f'Hello, {name}!'}
Enter fullscreen mode Exit fullscreen mode
# urls.py
from django.urls import path
from .api import api

urlpatterns = [
    path('api/', api.urls),
]
Enter fullscreen mode Exit fullscreen mode

That's it. Visit /api/docs for Swagger UI.

Schema Validation with Pydantic

from ninja import Schema
from datetime import datetime

class PostIn(Schema):
    title: str
    content: str
    tags: list[str] = []

class PostOut(Schema):
    id: int
    title: str
    content: str
    created: datetime

@api.post('/posts', response=PostOut)
def create_post(request, data: PostIn):
    post = Post.objects.create(**data.dict())
    return post
Enter fullscreen mode Exit fullscreen mode

CRUD with Django ORM

from ninja import Router
from django.shortcuts import get_object_or_404

router = Router()

@router.get('/posts', response=list[PostOut])
def list_posts(request):
    return Post.objects.all()

@router.get('/posts/{post_id}', response=PostOut)
def get_post(request, post_id: int):
    return get_object_or_404(Post, id=post_id)

@router.put('/posts/{post_id}', response=PostOut)
def update_post(request, post_id: int, data: PostIn):
    post = get_object_or_404(Post, id=post_id)
    for key, value in data.dict().items():
        setattr(post, key, value)
    post.save()
    return post

@router.delete('/posts/{post_id}')
def delete_post(request, post_id: int):
    post = get_object_or_404(Post, id=post_id)
    post.delete()
    return {'success': True}
Enter fullscreen mode Exit fullscreen mode

Authentication

from ninja.security import HttpBearer

class AuthBearer(HttpBearer):
    def authenticate(self, request, token):
        user = Token.objects.filter(key=token).first()
        if user:
            return user

@api.get('/protected', auth=AuthBearer())
def protected(request):
    return {'user': request.auth.username}
Enter fullscreen mode Exit fullscreen mode

File Uploads

from ninja import File, UploadedFile

@api.post('/upload')
def upload(request, file: UploadedFile = File(...)):
    data = file.read()
    return {'name': file.name, 'size': len(data)}
Enter fullscreen mode Exit fullscreen mode

Need to build a data API? Check out my Apify scrapers for ready-made data extraction, or email spinov001@gmail.com for custom Django API development.

Django REST Framework or Django Ninja — which do you prefer? Comment below!

Top comments (0)