KAHIBARO
Discord Login Register

7.11 Request Validation

Why Request Validation Matters

Request validation is the process of checking incoming data before your backend uses it. Every time a client sends data to your API, you must assume it might be:

If you skip validation, you risk:

Always validate all client input before using it or storing it. Never trust data just because it comes from your own frontend.

In REST APIs, validation usually happens:

You enforce rules that define what a "valid" request looks like, and you reject anything that does not match those rules.


Where Validation Happens in REST APIs

There are several common places to validate requests:

LocationTypical purposeExample
URL / Path parametersValidate identifiers and resource paths/users/{user_id} is an integer
Query parametersValidate filters, pagination, search options?page=1&limit=20
HeadersValidate auth tokens, content type, custom flagsAuthorization, Content-Type
Request body (JSON, form)Validate main data payloadUser registration data
FilesValidate file type, size, and countImage uploads

In a typical REST endpoint like:

text
POST /users/{user_id}/posts?page=1&limit=20
Content-Type: application/json
{
  "title": "Hello",
  "content": "My first post"
}

You might validate:

Types of Validation

Syntactic vs Semantic Validation

Two broad categories:

TypeQuestion it answersExample rule
Syntactic"Is the data structurally correct?"age must be an integer
Semantic"Does the data make sense logically?"start_date must be before end_date

Both are important.

Example

Request body:

json
{
  "email": "user@example.com",
  "age": 17,
  "plan": "premium"
}

Possible rules:

You usually do syntactic validation first, then semantic validation.


Common Validation Rules for REST APIs

Required and Optional Fields

Decide which fields are mandatory.

Example for user registration:

json
{
  "email": "user@example.com",
  "password": "secret123",
  "name": "Alice"
}

Possible rules:

Requests:

json
{ "email": "user@example.com" }        // Invalid, missing password
{ "email": "user@example.com", "password": "secret123", "name": "Alice" }  // Valid

Do not silently ignore missing required fields. Return a clear error describing what is wrong.

Data Types

Typical JSON types you validate:

FieldExpected typeInvalid examples
ageinteger"30", 30.5, true
pricenumber"9.99", null (if required)
is_activeboolean"true", 1
tagsarray of str"tag1,tag2", { "name": "tag1" }

If you expect integers in query params:

http
GET /products?limit=10

limit=abc should not be accepted.

String Length and Patterns

Examples:

You can express these as rules:

Passwords often have extra constraints, for example:

Numeric Ranges

Limit numeric values:

Example:

json
{ "age": -5 }     // Invalid
{ "age": 25 }     // Valid

For pagination:

http
GET /items?page=1&limit=5000

You might:

Always validate pagination input. It protects your server and database from very expensive queries.

Enumerations

Some fields only accept a limited set of values.

Examples:

Requests:

json
{ "status": "waiting" }   // Invalid
{ "status": "pending" }   // Valid

Using enums makes your API predictable and easier to document.

Date and Time

Common rules:

Example:

json
{
  "start_date": "2026-08-27",
  "end_date": "2026-08-26"
}

Invalid because start_date is after end_date.


Validating Different Parts of the Request

Path Parameters

For a URL like:

http
GET /users/{user_id}

Typical rules:

Examples:

If user_id is not found in your database, this is usually not a validation error, but a 404 Not Found.

Query Parameters

You often use query parameters for:

Example:

http
GET /tasks?status=completed&page=0&limit=200

Possible validation:

If query params are optional, you usually:

Example default behavior:

So /tasks behaves like /tasks?page=1&limit=20.

Headers

Important headers to validate:

Examples:

Invalid headers usually result in 400 Bad Request or 415 Unsupported Media Type, and auth problems in 401 Unauthorized.

Request Body: JSON Example

If you define a CreateUser payload:

json
{
  "email": "user@example.com",
  "password": "secret123",
  "age": 25
}

Rules might be:

Invalid examples:

json
{}  // Missing email and password
{
  "email": "not-an-email",
  "password": "short"
}
{
  "email": "user@example.com",
  "password": "longenough",
  "age": "twenty"
}

In each case you should explain which field failed and why.

Files

When handling file uploads, validate:

Example rules for profile picture:

Invalid cases:

For files, you usually combine:

Returning Validation Errors

Choosing HTTP Status Codes

Typical status codes for validation problems:

Status codeMeaningWhen to use
400Bad RequestGeneral invalid input, malformed JSON, wrong types
401UnauthorizedMissing or invalid authentication information
403ForbiddenAuthenticated, but not allowed to do this
404Not FoundResource does not exist
409ConflictConflicting state, like duplicate unique value
422Unprocessable EntityInput is well-formed JSON but fails validation rules

Many APIs use 400 for all client input errors. Others use 422 specifically for detailed validation errors.

Error Response Structure

Design a consistent error format. For example:

json
{
  "detail": [
    {
      "loc": ["body", "email"],
      "msg": "value is not a valid email address",
      "type": "value_error.email"
    },
    {
      "loc": ["body", "password"],
      "msg": "ensure this value has at least 8 characters",
      "type": "value_error.any_str.min_length"
    }
  ]
}

Here:

Another simpler style:

json
{
  "errors": {
    "email": "Invalid email format",
    "password": "Password must be at least 8 characters"
  }
}

Or:

json
{
  "message": "Validation failed",
  "errors": [
    { "field": "email", "error": "Invalid email format" },
    { "field": "password", "error": "Must be at least 8 characters" }
  ]
}

Use a consistent error response format across your entire API. Clients should be able to parse and handle validation errors automatically.


Validation in Create vs Update Operations

Create (POST)

On create endpoints, you often:

Example POST /users:

Missing required fields should cause a failure.

Full Update (PUT)

With PUT, the client often sends a full representation of the resource. You usually:

Example resource:

json
{
  "name": "Alice",
  "age": 25,
  "is_active": true
}

PUT payload:

json
{
  "name": "Alice Updated",
  "age": 26,
  "is_active": false
}

Validate as if it is a complete object.

Partial Update (PATCH)

With PATCH, the client sends only the fields it wants to change. Validation is trickier:

Example:

Current user:

json
{
  "email": "user@example.com",
  "age": 30
}

PATCH request:

json
{
  "age": 150
}

Here:

Another PATCH:

json
{}

This might be:

Business Rule Validation

After basic structure checks, you often validate business rules that involve:

Examples:

  1. Uniqueness
    • email must be unique.

Process:

  1. Resource existence
    • project_id in payload must refer to an existing project.

If project does not exist:

  1. State-dependent rules
    • User cannot cancel an order that is already shipped.

Steps:

json
   {
     "message": "Order cannot be canceled in state 'shipped'"
   }

Idempotency and Validation

Idempotent methods like GET, PUT, and often DELETE should behave predictably. Validation helps ensure that:

Example for a payment API with an idempotency key:

This is especially important in payment, booking, or order APIs.


Practical Examples

Below are language-agnostic examples of validation scenarios to help you think clearly about how to design them.

Example 1: Creating a Task

Endpoint:

http
POST /tasks
Content-Type: application/json

Request body:

json
{
  "title": "Buy groceries",
  "description": "Milk, eggs, bread",
  "priority": 3,
  "due_date": "2026-09-01"
}

Validation rules:

Invalid request 1 (missing title):

json
{
  "description": "Milk, eggs, bread"
}

Response:

http
400 Bad Request
json
{
  "message": "Validation failed",
  "errors": {
    "title": "This field is required"
  }
}

Invalid request 2 (priority out of range):

json
{
  "title": "Buy groceries",
  "priority": 10
}

Response:

http
422 Unprocessable Entity
json
{
  "errors": {
    "priority": "Must be between 1 and 5"
  }
}

Example 2: Pagination Parameters

Endpoint:

http
GET /products?page=0&limit=500

Rules:

Invalid query:

Response:

http
400 Bad Request
json
{
  "errors": {
    "page": "Must be >= 1",
    "limit": "Must be between 1 and 100"
  }
}

Valid query with defaults:

http
GET /products

Server treats it as page=1&limit=20.

Example 3: Enum and Business Rule Combined

Endpoint:

http
PATCH /orders/123/status
Content-Type: application/json

Request:

json
{ "status": "shipped" }

Rules:

Possible invalid cases:

  1. Invalid enum:
json
   { "status": "sending" }

Return validation error:

json
   {
     "errors": {
       "status": "Invalid value, must be one of: pending, paid, shipped, delivered, canceled"
     }
   }
  1. Invalid state transition:
    • Order is currently "pending" in database.
    • Client sends "shipped".

Here the value is syntactically valid but breaks a business rule. Return something like:

json
   {
     "message": "Order status cannot change from 'pending' to 'shipped'"
   }

You might use 400 Bad Request or 409 Conflict depending on your API style.


Designing Validation Rules Up Front

Before implementing an endpoint, define its validation rules clearly. For each field, decide:

Field nameLocationRequired?TypeRules / constraints
titlebodyyesstring1 to 100 characters
descriptionbodynostringmax 1000 characters
prioritybodynointeger1 to 5, default 3
due_datebodynodatemust not be in the past
pagequerynointegermin 1, default 1
limitquerynointegermin 1, max 100, default 20
idpathyesintegerpositive
Authorizationheaderyesstring, Bearermust contain valid token and correspond to a user

This table-like approach makes it easy to:

Later, when you use tools like OpenAPI and libraries such as Pydantic or others in real code, these rules translate directly into schemas and types.


Best Practices Summary

With these principles, your REST APIs become safer, more predictable, and much easier for other developers to use.

Views: 10

Comments

Please login to add a comment.

Don't have an account? Register now!