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 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: Sun, 26 Apr 2026 21:12:31 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, 422, 406]","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"
      }
    },
    "securitySchemes": {}
  },
  "info": {
    "title": "Django Modern Rest",
    "version": "0.1.0"
  },
  "openapi": "3.2.0",
  "paths": {
    "/api/usercontroller/": {
      "post": {
        "deprecated": false,
        "operationId": "postUsercontrollerApiUsercontroller",
        "parameters": [
          {
            "deprecated": false,
            "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"
          }
        }
      }
    }
  }
}

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: Sun, 26 Apr 2026 21:12:33 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