Response validation#

By default, all responses (not just requests!) are validated at runtime to match the schema. This allows us to be super strict about schema generation as a pro, but as a con, it is slower than it could possibly be.

So, you can disable response validation via the configuration:

Warning

Disabling response validation makes sense only in production for better performance.

It is not recommended to disable response validation for any other reason. Instead, fix your schema errors!

Keep it on in development, but disable it in production to get the best of both worlds.

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"}

$ curl http://127.0.0.1:8000/api/user/ -D - -X POST -d '{"email": "user@wms.org"}' -H 'Content-Type: application/json' -H 'X-API-Consumer: not-my-api'
HTTP/1.1 422 Unprocessable Entity
date: Mon, 05 Oct 2026 11:19:01 GMT
server: uvicorn
Content-Type: application/json
X-Frame-Options: DENY
Vary: Accept-Language
Content-Language: en
Content-Length: 143
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Cross-Origin-Opener-Policy: same-origin

{"detail":[{"msg":"Returned status code 402 is not specified in the list of allowed status codes: [201, 400, 406, 422]","type":"value_error"}]}

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"
      },
      "UserModel": {
        "properties": {
          "email": {
            "type": "string"
          }
        },
        "required": [
          "email"
        ],
        "title": "UserModel",
        "type": "object"
      }
    }
  },
  "info": {
    "title": "Django Modern Rest",
    "version": "0.1.0"
  },
  "openapi": "3.2.0",
  "paths": {
    "/api/usercontroller/": {
      "post": {
        "operationId": "postUserControllerApiUsercontroller",
        "parameters": [
          {
            "in": "header",
            "name": "X-API-Consumer",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserModel"
              }
            }
          },
          "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"
          }
        }
      }
    }
  }
}

Excluding some status codes#

Added in version 0.15.0.

Sometimes you don’t want to disable the validation completely, you just have status codes that are not in your schema. 500 is the usual one.

List them in exclude_validate_responses to let such responses through:

settings.py#
>>> from http import HTTPStatus
>>> from dmr.settings import Settings

>>> DMR_SETTINGS = {
...     Settings.exclude_validate_responses: {
...         HTTPStatus.INTERNAL_SERVER_ERROR,
...     },
... }

The same works per-controller with exclude_validate_responses and per-endpoint with the argument of the same name to modify and validate. Setting it to None on any level resets all the other levels.

All other status codes are still validated as usual. See Validating error responses for when this is the right call and what the alternatives are.

The right way#

The “right way” is not to disable the validation, but to specify the correct schema to be returned from an endpoint.

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"}

$ curl http://127.0.0.1:8000/api/user/ -D - -X POST -d '{"email": "user@wms.org"}' -H 'Content-Type: application/json' -H 'X-API-Consumer: not-my-api'
HTTP/1.1 402 Payment Required
date: Mon, 05 Oct 2026 11:19:03 GMT
server: uvicorn
Content-Type: application/json
X-Frame-Options: DENY
Vary: Accept-Language
Content-Language: en
Content-Length: 59
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Cross-Origin-Opener-Policy: same-origin

{"detail":[{"msg":"Wrong API consumer","type":"user_msg"}]}

And to disable the validation for production environment. Example: https://github.com/wemake-services/wemake-django-template/blob/c003757fd33ba7dd1a9e7af7c3a175883d0c033b/%7B%7Bcookiecutter.project_name%7D%7D/server/settings/environments/production.py#L86