Getting started¶
Installation¶
Works for:
CPython 3.11+ or PyPy 3.11+
Django 4.2+
uv add django-modern-rest
poetry add django-modern-rest
pip install django-modern-rest
Extras for different serializers:
'django-modern-rest[pydantic]'forpydanticsupport'django-modern-rest[attrs]'forattrssupport'django-modern-rest[msgspec]'formsgspecsupport and the fastestjsonparsing
Extras for different features:
'django-modern-rest[jwt]'for jwt support'django-modern-rest[openapi]'for OpenAPI schema validation and better examples generation
Important
We highly recommend to always install
msgspec, even when using just
pydantic for APIs,
because we use msgspec to parse json, when it is available,
since it is the fastest
library out there for this task.
We also recommend to always install django-stubs for typing the Django itself.
Note
You don’t need to add 'dmr' to the INSTALLED_APPS,
unless you want to serve static files for the OpenAPI.
LLMs support¶
Are you using AI for assisted coding? We got you covered, use these files for context to make sure that the LLM knows our framework:
https://django-modern-rest.readthedocs.io/llms.txt for indexes with links to different pages and topics
https://django-modern-rest.readthedocs.io/llms-full.txt for complete docs
We also support Context7 for up-to-date docs for the LLMs.
Use cases we officially support:
Learning
django-modern-restwith the help of DeepWikiAI-guided migrations for any API changes. We break something? We provide a prompt for you, so you can automatically upgrade to a newer version using an AI tool of your choice
We support several custom agent skills:
$dmrto enforcedjango-modern-restbest practices with fast and secure approaches$dmr-openapi-skeletonto generate a working project boilerplate from a singleopenapi.jsonfile (the “Spec First” approach)$dmr-from-django-ninjato help with migrating from Django Ninja$dmr-from-drfto help with migrating from Django REST Framework
Showcase¶
Let’s see the basics and learn how to use dmr in a single example:
We support msgspec.Struct
via MsgspecSerializer.
1import uuid
2
3import msgspec
4
5from dmr import Body, Controller
6from dmr.plugins.msgspec import MsgspecSerializer
7
8
9class UserCreateModel(msgspec.Struct):
10 email: str
11
12
13class UserModel(UserCreateModel):
14 uid: uuid.UUID
15
16
17class UserController(Controller[MsgspecSerializer]):
18 def post(self, parsed_body: Body[UserCreateModel]) -> UserModel:
19 return UserModel(uid=uuid.uuid4(), email=parsed_body.email)
20
Run result
$ curl http://127.0.0.1:8000/api/user/ -X POST -d '{"email": "email@example.com"}' -H 'Content-Type: application/json'
{"email":"email@example.com","uid":"361c5d87-e4d8-4255-9e80-6013c9ab1c85"}
OpenAPI Schema
Preview openapi.json
{
"components": {
"schemas": {
"ErrorDetail": {
"description": "Base schema for error details description.",
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"type": "array"
},
"msg": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"msg"
],
"title": "ErrorDetail",
"type": "object"
},
"ErrorModel": {
"description": "Default error response schema.\n\nCan be customized.\nSee :ref:`customizing-error-messages` for more details.",
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ErrorDetail"
},
"type": "array"
}
},
"required": [
"detail"
],
"title": "ErrorModel",
"type": "object"
},
"UserCreateModel": {
"properties": {
"email": {
"type": "string"
}
},
"required": [
"email"
],
"title": "UserCreateModel",
"type": "object"
},
"UserModel": {
"properties": {
"email": {
"type": "string"
},
"uid": {
"format": "uuid",
"type": "string"
}
},
"required": [
"email",
"uid"
],
"title": "UserModel",
"type": "object"
}
},
"securitySchemes": {}
},
"info": {
"title": "Django Modern Rest",
"version": "0.1.0"
},
"openapi": "3.2.0",
"paths": {
"/api/usercontroller/": {
"post": {
"deprecated": false,
"operationId": "postUsercontrollerApiUsercontroller",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserCreateModel"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserModel"
}
}
},
"description": "Created"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when request components cannot be parsed"
},
"406": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when provided `Accept` header cannot be satisfied"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when returned response does not match the response schema"
}
}
}
}
}
}
We support pydantic.BaseModel
via PydanticSerializer.
Tip
If you only use json parsers and renderers,
it would be faster to use
PydanticFastSerializer instead.
1import uuid
2
3import pydantic
4
5from dmr import Body, Controller
6from dmr.plugins.pydantic import PydanticSerializer
7
8
9class UserCreateModel(pydantic.BaseModel):
10 email: str
11
12
13class UserModel(UserCreateModel):
14 uid: uuid.UUID
15
16
17class UserController(Controller[PydanticSerializer]):
18 def post(self, parsed_body: Body[UserCreateModel]) -> UserModel:
19 return UserModel(uid=uuid.uuid4(), email=parsed_body.email)
20
Run result
$ curl http://127.0.0.1:8000/api/user/ -X POST -d '{"email": "email@example.com"}' -H 'Content-Type: application/json'
{"email":"email@example.com","uid":"c804f811-4891-4e13-a4d4-45d30d2531e3"}
OpenAPI Schema
Preview openapi.json
{
"components": {
"schemas": {
"ErrorDetail": {
"description": "Base schema for error details description.",
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"title": "Loc",
"type": "array"
},
"msg": {
"title": "Msg",
"type": "string"
},
"type": {
"title": "Type",
"type": "string"
}
},
"required": [
"msg"
],
"title": "ErrorDetail",
"type": "object"
},
"ErrorModel": {
"description": "Default error response schema.\n\nCan be customized.\nSee :ref:`customizing-error-messages` for more details.",
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ErrorDetail"
},
"title": "Detail",
"type": "array"
}
},
"required": [
"detail"
],
"title": "ErrorModel",
"type": "object"
},
"UserCreateModel": {
"properties": {
"email": {
"title": "Email",
"type": "string"
}
},
"required": [
"email"
],
"title": "UserCreateModel",
"type": "object"
},
"UserModel": {
"properties": {
"email": {
"title": "Email",
"type": "string"
},
"uid": {
"format": "uuid",
"title": "Uid",
"type": "string"
}
},
"required": [
"email",
"uid"
],
"title": "UserModel",
"type": "object"
}
},
"securitySchemes": {}
},
"info": {
"title": "Django Modern Rest",
"version": "0.1.0"
},
"openapi": "3.2.0",
"paths": {
"/api/usercontroller/": {
"post": {
"deprecated": false,
"operationId": "postUsercontrollerApiUsercontroller",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserCreateModel"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserModel"
}
}
},
"description": "Created"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when request components cannot be parsed"
},
"406": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when provided `Accept` header cannot be satisfied"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when returned response does not match the response schema"
}
}
}
}
}
}
We support attrs.define()
via MsgspecSerializer.
See msgspec docs
on attrs support.
1import uuid
2
3import attrs
4
5from dmr import Body, Controller
6from dmr.plugins.msgspec import MsgspecSerializer
7
8
9@attrs.define
10class UserCreateModel:
11 email: str
12
13
14@attrs.define
15class UserModel(UserCreateModel):
16 uid: uuid.UUID
17
18
19class UserController(Controller[MsgspecSerializer]):
20 def post(self, parsed_body: Body[UserCreateModel]) -> UserModel:
21 return UserModel(uid=uuid.uuid4(), email=parsed_body.email)
22
Run result
$ curl http://127.0.0.1:8000/api/user/ -X POST -d '{"email": "email@example.com"}' -H 'Content-Type: application/json'
{"uid":"1783b197-27e1-4b97-9efb-d42eeebef415","email":"email@example.com"}
OpenAPI Schema
Preview openapi.json
{
"components": {
"schemas": {
"ErrorDetail": {
"description": "Base schema for error details description.",
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"type": "array"
},
"msg": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"msg"
],
"title": "ErrorDetail",
"type": "object"
},
"ErrorModel": {
"description": "Default error response schema.\n\nCan be customized.\nSee :ref:`customizing-error-messages` for more details.",
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ErrorDetail"
},
"type": "array"
}
},
"required": [
"detail"
],
"title": "ErrorModel",
"type": "object"
},
"UserCreateModel": {
"properties": {
"email": {
"type": "string"
}
},
"required": [
"email"
],
"title": "UserCreateModel",
"type": "object"
},
"UserModel": {
"properties": {
"email": {
"type": "string"
},
"uid": {
"format": "uuid",
"type": "string"
}
},
"required": [
"email",
"uid"
],
"title": "UserModel",
"type": "object"
}
},
"securitySchemes": {}
},
"info": {
"title": "Django Modern Rest",
"version": "0.1.0"
},
"openapi": "3.2.0",
"paths": {
"/api/usercontroller/": {
"post": {
"deprecated": false,
"operationId": "postUsercontrollerApiUsercontroller",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserCreateModel"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserModel"
}
}
},
"description": "Created"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when request components cannot be parsed"
},
"406": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when provided `Accept` header cannot be satisfied"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when returned response does not match the response schema"
}
}
}
}
}
}
We support dataclasses.dataclass() via both
MsgspecSerializer
and PydanticSerializer.
1import dataclasses
2import uuid
3
4from dmr import Body, Controller
5from dmr.plugins.msgspec import MsgspecSerializer
6
7
8@dataclasses.dataclass
9class UserCreateModel:
10 email: str
11
12
13@dataclasses.dataclass
14class UserModel(UserCreateModel):
15 uid: uuid.UUID
16
17
18class UserController(Controller[MsgspecSerializer]):
19 def post(self, parsed_body: Body[UserCreateModel]) -> UserModel:
20 return UserModel(uid=uuid.uuid4(), email=parsed_body.email)
21
Run result
$ curl http://127.0.0.1:8000/api/user/ -X POST -d '{"email": "email@example.com"}' -H 'Content-Type: application/json'
{"email":"email@example.com","uid":"b8f19f78-54f0-40e2-a29d-e58b07261f82"}
OpenAPI Schema
Preview openapi.json
{
"components": {
"schemas": {
"ErrorDetail": {
"description": "Base schema for error details description.",
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"type": "array"
},
"msg": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"msg"
],
"title": "ErrorDetail",
"type": "object"
},
"ErrorModel": {
"description": "Default error response schema.\n\nCan be customized.\nSee :ref:`customizing-error-messages` for more details.",
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ErrorDetail"
},
"type": "array"
}
},
"required": [
"detail"
],
"title": "ErrorModel",
"type": "object"
},
"UserCreateModel": {
"properties": {
"email": {
"type": "string"
}
},
"required": [
"email"
],
"title": "UserCreateModel",
"type": "object"
},
"UserModel": {
"properties": {
"email": {
"type": "string"
},
"uid": {
"format": "uuid",
"type": "string"
}
},
"required": [
"email",
"uid"
],
"title": "UserModel",
"type": "object"
}
},
"securitySchemes": {}
},
"info": {
"title": "Django Modern Rest",
"version": "0.1.0"
},
"openapi": "3.2.0",
"paths": {
"/api/usercontroller/": {
"post": {
"deprecated": false,
"operationId": "postUsercontrollerApiUsercontroller",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserCreateModel"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserModel"
}
}
},
"description": "Created"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when request components cannot be parsed"
},
"406": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when provided `Accept` header cannot be satisfied"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when returned response does not match the response schema"
}
}
}
}
}
}
We support typing.TypedDict via both
MsgspecSerializer
and PydanticSerializer.
1import uuid
2from typing import TypedDict
3
4from dmr import Body, Controller
5from dmr.plugins.msgspec import MsgspecSerializer
6
7
8class UserCreateModel(TypedDict):
9 email: str
10
11
12class UserModel(UserCreateModel):
13 uid: uuid.UUID
14
15
16class UserController(Controller[MsgspecSerializer]):
17 def post(self, parsed_body: Body[UserCreateModel]) -> UserModel:
18 return UserModel(uid=uuid.uuid4(), email=parsed_body['email'])
19
Run result
$ curl http://127.0.0.1:8000/api/user/ -X POST -d '{"email": "email@example.com"}' -H 'Content-Type: application/json'
{"uid":"cf4a0411-08b6-49d7-907b-79315bdfa79e","email":"email@example.com"}
OpenAPI Schema
Preview openapi.json
{
"components": {
"schemas": {
"ErrorDetail": {
"description": "Base schema for error details description.",
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"type": "array"
},
"msg": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"msg"
],
"title": "ErrorDetail",
"type": "object"
},
"ErrorModel": {
"description": "Default error response schema.\n\nCan be customized.\nSee :ref:`customizing-error-messages` for more details.",
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ErrorDetail"
},
"type": "array"
}
},
"required": [
"detail"
],
"title": "ErrorModel",
"type": "object"
},
"UserCreateModel": {
"properties": {
"email": {
"type": "string"
}
},
"required": [
"email"
],
"title": "UserCreateModel",
"type": "object"
},
"UserModel": {
"properties": {
"email": {
"type": "string"
},
"uid": {
"format": "uuid",
"type": "string"
}
},
"required": [
"email",
"uid"
],
"title": "UserModel",
"type": "object"
}
},
"securitySchemes": {}
},
"info": {
"title": "Django Modern Rest",
"version": "0.1.0"
},
"openapi": "3.2.0",
"paths": {
"/api/usercontroller/": {
"post": {
"deprecated": false,
"operationId": "postUsercontrollerApiUsercontroller",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserCreateModel"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserModel"
}
}
},
"description": "Created"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when request components cannot be parsed"
},
"406": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when provided `Accept` header cannot be satisfied"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when returned response does not match the response schema"
}
}
}
}
}
}
We support typing.NamedTuple
via PydanticSerializer.
1import uuid
2from typing import NamedTuple
3
4from dmr import Body, Controller
5from dmr.plugins.pydantic import PydanticSerializer
6
7
8class UserCreateModel(NamedTuple):
9 email: str
10
11
12class UserModel(NamedTuple):
13 email: str
14 uid: uuid.UUID
15
16
17class UserController(Controller[PydanticSerializer]):
18 def post(self, parsed_body: Body[UserCreateModel]) -> UserModel:
19 return UserModel(uid=uuid.uuid4(), email=parsed_body.email)
20
Run result
$ curl http://127.0.0.1:8000/api/user/ -X POST -d '{"email": "email@example.com"}' -H 'Content-Type: application/json'
["email@example.com","75cdf27d-f032-45df-8b48-ee257867f3c2"]
OpenAPI Schema
Preview openapi.json
{
"components": {
"schemas": {
"ErrorDetail": {
"description": "Base schema for error details description.",
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"title": "Loc",
"type": "array"
},
"msg": {
"title": "Msg",
"type": "string"
},
"type": {
"title": "Type",
"type": "string"
}
},
"required": [
"msg"
],
"title": "ErrorDetail",
"type": "object"
},
"ErrorModel": {
"description": "Default error response schema.\n\nCan be customized.\nSee :ref:`customizing-error-messages` for more details.",
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ErrorDetail"
},
"title": "Detail",
"type": "array"
}
},
"required": [
"detail"
],
"title": "ErrorModel",
"type": "object"
}
},
"securitySchemes": {}
},
"info": {
"title": "Django Modern Rest",
"version": "0.1.0"
},
"openapi": "3.2.0",
"paths": {
"/api/usercontroller/": {
"post": {
"deprecated": false,
"operationId": "postUsercontrollerApiUsercontroller",
"requestBody": {
"content": {
"application/json": {
"schema": {
"maxItems": 1,
"minItems": 1,
"prefixItems": [
{
"title": "Email",
"type": "string"
}
],
"type": "array"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"maxItems": 2,
"minItems": 2,
"prefixItems": [
{
"title": "Email",
"type": "string"
},
{
"format": "uuid",
"title": "Uid",
"type": "string"
}
],
"type": "array"
}
}
},
"description": "Created"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when request components cannot be parsed"
},
"406": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when provided `Accept` header cannot be satisfied"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when returned response does not match the response schema"
}
}
}
}
}
}
Important
You can choose a serializer per controller, which will give you
the freedom to choose the best serializer and model for the job.
msgspec gives you more speed,
while pydantic gives you more flexibility.
In this example:
We defined regular
pydantic,msgspec, or whatever models that we will use for our APIWe added two component parsers: one for request’s
Bodyand one forHeaderswhich will parse them into the typed models that we pass to these components as type parametersNext we created a
Controllerclass withPydanticSerializerorMsgspecSerializerto serialize input and output data for usWe also defined
postAPI endpoint and returned a simple model response from it, it will be automatically transformed intodjango.http.HttpResponseinstance bydjango-modern-rest
Now, let’s add our controller to the list of URLs:
1from django.urls import include
2
3# Our `path` is an optimized drop-in replacement of `django.urls.path`:
4from dmr.routing import Router, path
5from examples.getting_started.pydantic_controller import UserController
6
7# Router is just a collection of regular Django urls:
8router = Router(
9 'api/',
10 [
11 path(
12 'user/',
13 UserController.as_view(),
14 name='users',
15 ),
16 ],
17)
18
19# Just a regular `urlpatterns` definition, Django-style:
20urlpatterns = [
21 path(router.prefix, include((router.urls, 'rest_app'), namespace='api')),
22]
Run result
$ curl http://127.0.0.1:8000/api/user/ -X POST -d '{"email": "user@wms.org"}' -H 'Content-Type: application/json' -H 'X-API-Consumer: my-api'
{"email":"user@wms.org","uid":"2db7687c-597c-4c2e-a6ee-f6eb9bca4eba"}
Your first django-modern-rest API is ready.
Next, you can learn:
How to generate OpenAPI schema
How to handle errors
How to customize controllers and endpoints
Full example¶
If you were ever told that Django is too big and complicated, that was misleading, to say the least.
Here’s a single-file application that looks pretty much the same as any other micro-framework, like: FastAPI, Litestar, or Flask.
1import secrets
2import sys
3import uuid
4
5import pydantic
6from django.conf import settings
7from django.core.management import execute_from_command_line
8from django.urls import include
9
10from dmr import Body, Controller
11from dmr.openapi import build_schema
12from dmr.openapi.views import OpenAPIJsonView, SwaggerView
13from dmr.plugins.pydantic import PydanticSerializer
14from dmr.routing import Router, path
15
16if not settings.configured:
17 settings.configure(
18 ROOT_URLCONF=__name__,
19 ALLOWED_HOSTS='*',
20 DEBUG=True,
21 INSTALLED_APPS=['dmr', 'django.contrib.staticfiles'],
22 STATIC_URL='/static/',
23 STATICFILES_FINDERS=[
24 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
25 ],
26 TEMPLATES=[
27 {
28 'APP_DIRS': True,
29 'BACKEND': 'django.template.backends.django.DjangoTemplates',
30 },
31 ],
32 # Secret key for tests, will be new on each run,
33 # in production it must be the same token, kept in secret:
34 SECRET_KEY=secrets.token_hex(),
35 )
36
37
38class UserCreateModel(pydantic.BaseModel):
39 email: str
40
41
42class UserResponseModel(UserCreateModel):
43 uid: uuid.UUID
44
45
46class UserController(Controller[PydanticSerializer]):
47 async def post(
48 self,
49 parsed_body: Body[UserCreateModel],
50 ) -> UserResponseModel:
51 return UserResponseModel(uid=uuid.uuid4(), email=parsed_body.email)
52
53
54router = Router(
55 'api/',
56 [
57 path('user/', UserController.as_view(), name='users'),
58 ],
59)
60schema = build_schema(router)
61
62urlpatterns = [
63 path(router.prefix, include((router.urls, 'your_app'), namespace='api')),
64 path('docs/openapi.json/', OpenAPIJsonView.as_view(schema), name='openapi'),
65 path('docs/swagger/', SwaggerView.as_view(schema), name='swagger'),
66]
67
68if __name__ == '__main__':
69 # Use `python THIS_FILE_NAME.py runserver` to run the example.
70 # Then visit `http://localhost:8000/docs/swagger` to view the docs.
71 execute_from_command_line(sys.argv)
Run result
$ curl http://127.0.0.1:8000/api/user/ -X POST -d '{"email": "djangomodernrest@wemake.services"}' -H 'Content-Type: application/json'
{"email":"djangomodernrest@wemake.services","uid":"44bb0400-8889-4ea8-adb1-1d37393d4f43"}
OpenAPI Schema
Preview openapi.json
{
"components": {
"schemas": {
"ErrorDetail": {
"description": "Base schema for error details description.",
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"title": "Loc",
"type": "array"
},
"msg": {
"title": "Msg",
"type": "string"
},
"type": {
"title": "Type",
"type": "string"
}
},
"required": [
"msg"
],
"title": "ErrorDetail",
"type": "object"
},
"ErrorModel": {
"description": "Default error response schema.\n\nCan be customized.\nSee :ref:`customizing-error-messages` for more details.",
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ErrorDetail"
},
"title": "Detail",
"type": "array"
}
},
"required": [
"detail"
],
"title": "ErrorModel",
"type": "object"
},
"UserCreateModel": {
"properties": {
"email": {
"title": "Email",
"type": "string"
}
},
"required": [
"email"
],
"title": "UserCreateModel",
"type": "object"
},
"UserResponseModel": {
"properties": {
"email": {
"title": "Email",
"type": "string"
},
"uid": {
"format": "uuid",
"title": "Uid",
"type": "string"
}
},
"required": [
"email",
"uid"
],
"title": "UserResponseModel",
"type": "object"
}
},
"securitySchemes": {}
},
"info": {
"title": "Django Modern Rest",
"version": "0.1.0"
},
"openapi": "3.2.0",
"paths": {
"/api/user/": {
"post": {
"deprecated": false,
"operationId": "postUsercontrollerApiUser",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserCreateModel"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserResponseModel"
}
}
},
"description": "Created"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when request components cannot be parsed"
},
"406": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when provided `Accept` header cannot be satisfied"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when returned response does not match the response schema"
}
}
}
}
}
}
You can copy it by clicking “Copy” in the right upper corner of the example,
it shows up on hovering the code example. Paste it as example.py,
install the django-modern-rest and run it with:
uv run example.py runserver
poetry run python example.py runserver
python example.py runserver
Your API is now live:
POSThttp://localhost:8000/api/user/ — create a user
And then visit https://localhost:8000/docs/swagger/ for the interactive docs.
That’s it, enjoy your new project!
But, this is too simple for my use-case!¶
What is great about Django is that it scales. You can start with a single file app and scale it up to a full featured monolith with strict context boundaries, DDD, reusable apps, etc.
We recommend starting new big projects with https://github.com/wemake-services/wemake-django-template
It is strict, security-first, battle-proven, highload-tested boilerplate for real apps of the modern age.
Next up¶
Learn the fundamentals.
Learn how to configure django-modern-rest.