This skill should be used when the user asks to "create api endpoint", "django ninja", "django api", "add endpoint", "rest api django", "ninja router", "api schemas", or mentions API development, endpoint organization, or Pydantic schemas in Django projects. Provides Django Ninja patterns with 1-endpoint-per-file organization.
/plugin marketplace add sergio-bershadsky/ai/plugin install django-dev@bershadsky-claude-toolsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/endpoints.mdreferences/routers.mdOpinionated Django Ninja patterns with single-endpoint-per-file organization.
schemas/myapp/
├── api/
│ ├── __init__.py # Main NinjaAPI instance
│ ├── users/
│ │ ├── __init__.py # Router: users_router
│ │ ├── list.py # GET /users/
│ │ ├── detail.py # GET /users/{id}
│ │ ├── create.py # POST /users/
│ │ ├── update.py # PUT /users/{id}
│ │ └── delete.py # DELETE /users/{id}
│ ├── products/
│ │ ├── __init__.py
│ │ ├── list.py
│ │ ├── detail.py
│ │ └── search.py
│ └── auth/
│ ├── __init__.py
│ ├── login.py
│ ├── logout.py
│ └── refresh.py
└── schemas/
├── __init__.py
├── user.py # UserIn, UserOut, UserPatch
├── product.py
└── common.py # Pagination, errors
In api/__init__.py:
from ninja import NinjaAPI
from ninja.security import HttpBearer
from .users import router as users_router
from .products import router as products_router
from .auth import router as auth_router
class AuthBearer(HttpBearer):
def authenticate(self, request, token):
# Token validation logic
from ..services.auth import AuthService
return AuthService.validate_token(token)
api = NinjaAPI(
title="My API",
version="1.0.0",
description="API documentation",
auth=AuthBearer(),
)
# Register routers
api.add_router("/users", users_router, tags=["Users"])
api.add_router("/products", products_router, tags=["Products"])
api.add_router("/auth", auth_router, tags=["Authentication"], auth=None)
Each group has a router in __init__.py:
# api/users/__init__.py
from ninja import Router
from .list import router as list_router
from .detail import router as detail_router
from .create import router as create_router
from .update import router as update_router
from .delete import router as delete_router
router = Router()
# Merge endpoint routers
router.add_router("", list_router)
router.add_router("", detail_router)
router.add_router("", create_router)
router.add_router("", update_router)
router.add_router("", delete_router)
Each endpoint in its own file:
# api/users/create.py
from ninja import Router
from django.http import HttpRequest
from ...schemas.user import UserIn, UserOut
from ...services.user import UserService
router = Router()
@router.post("/", response={201: UserOut})
def create_user(request: HttpRequest, payload: UserIn) -> UserOut:
"""Create a new user."""
user = UserService.create(payload)
return user
Pydantic schemas in schemas/ package:
# schemas/user.py
from uuid import UUID
from datetime import datetime
from pydantic import BaseModel, EmailStr, Field
class UserBase(BaseModel):
"""Shared user fields."""
email: EmailStr
name: str = Field(max_length=255)
class UserIn(UserBase):
"""Input schema for creating users."""
password: str = Field(min_length=8)
class UserPatch(BaseModel):
"""Partial update schema."""
email: EmailStr | None = None
name: str | None = Field(None, max_length=255)
class UserOut(UserBase):
"""Output schema for users."""
id: UUID
is_active: bool
created_at: datetime
class Config:
from_attributes = True
# schemas/common.py
from typing import Generic, TypeVar, List
from pydantic import BaseModel
T = TypeVar("T")
class PaginatedResponse(BaseModel, Generic[T]):
items: List[T]
total: int
page: int
per_page: int
pages: int
# api/users/list.py
from ninja import Router, Query
from ...schemas.user import UserOut
from ...schemas.common import PaginatedResponse
router = Router()
@router.get("/", response=PaginatedResponse[UserOut])
def list_users(
request,
page: int = Query(1, ge=1),
per_page: int = Query(20, ge=1, le=100),
):
"""List users with pagination."""
from ...services.user import UserService
return UserService.list_paginated(page, per_page)
# schemas/common.py
class ErrorResponse(BaseModel):
detail: str
code: str | None = None
class ValidationErrorResponse(BaseModel):
detail: list[dict]
# api/users/detail.py
from ninja import Router
from django.http import Http404
from ...schemas.user import UserOut
from ...schemas.common import ErrorResponse
router = Router()
@router.get("/{user_id}", response={200: UserOut, 404: ErrorResponse})
def get_user(request, user_id: UUID):
"""Get user by ID."""
from ...services.user import UserService
user = UserService.get_by_id(user_id)
if not user:
return 404, {"detail": "User not found", "code": "USER_NOT_FOUND"}
return user
# api/files/upload.py
from ninja import Router, File, UploadedFile
from ...schemas.file import FileOut
router = Router()
@router.post("/upload", response=FileOut)
def upload_file(request, file: UploadedFile = File(...)):
"""Upload a file."""
from ...services.file import FileService
return FileService.save(file)
Register API in urls.py:
# config/urls.py
from django.urls import path
from apps.myapp.api import api
urlpatterns = [
path("api/", api.urls),
]
See references/endpoints.md for detailed authentication patterns including:
references/endpoints.md - Detailed endpoint patterns, authentication, permissionsreferences/routers.md - Router organization, versioning, OpenAPI customizationThis skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.