REST API Input Validation
Every request carries data that the server did not create. Some of it is correct, some of it is careless, and some of it is crafted to cause harm. Input validation checks data at the door before the application uses it.
The Airport Check Picture
Airports inspect every bag before passengers board. Inspectors do not assume that every traveler means well. They check each item against clear rules. A server treats incoming requests the same way, and it checks every field before processing.
Where Validation Happens
Request arrives
│
▼
1. Syntax check Is the body valid JSON?
2. Structure check Are required fields present, with the right types?
3. Rule check Are values within allowed ranges and formats?
4. Business check Does the action make sense for this user and state?
│
▼
Pass: process the request Fail: return an error response
Client Checks vs Server Checks
Forms in apps and browsers can validate fields to give instant feedback. Those checks improve the user experience, and they offer no protection. Anyone can skip the form and call the API directly. The server must validate every request on its own.
What to Validate
| Check | Sample Rule |
|---|---|
| Type | age must be a whole number |
| Required | email must be present |
| Length | name holds 1 to 100 characters |
| Range | quantity holds a number from 1 to 500 |
| Format | email matches an address pattern |
| Allowed list | status equals pending, paid, or shipped |
| Size | request body stays under 1 MB |
Allowlists Beat Blocklists
A blocklist names bad values, and attackers invent new ones. An allowlist names the good values and rejects everything else. Accept only known fields, known types, and known choices.
Reject Unknown Fields
A client might send an extra field such as "role": "admin" in a profile update. A server that copies every incoming field into the database hands out privileges for free. Map each accepted field by name and ignore or reject the rest.
Protect Against Injection
Never build database queries by joining strings with user input. Use parameterized queries, where the database receives the command and the values separately.
Risky: "SELECT * FROM users WHERE email = '" + input + "'" Safe: "SELECT * FROM users WHERE email = ?" with value from input
Encode output that reaches web pages, and avoid passing input into shell commands or file paths.
Choose the Right Status Code
- 400 Bad Request: the body is not valid JSON, or a required structure is broken.
- 422 Unprocessable Content: the JSON is valid and a field breaks a rule.
- 413 Content Too Large: the body exceeds the size limit.
- 415 Unsupported Media Type: the format is not accepted.
Report All Errors at Once
A response that lists every problem saves users from fixing one error per attempt.
HTTP/1.1 422 Unprocessable Content
{
"error": "validation_failed",
"details": [
{ "field": "email", "message": "must be a valid address" },
{ "field": "quantity", "message": "must be between 1 and 500" }
]
}
Write messages that describe the rule, and leave out internal details such as stack traces or table names.
Normalize Before Checking
Trim spaces, convert text to a consistent Unicode form, and lowercase email addresses before applying rules. Normalization removes sneaky variations that slip past checks.
Common Mistakes
Trusting the Front End
Browser checks vanish when someone calls the API with a script. Validate on the server every time.
Validating Only Some Endpoints
A forgotten endpoint becomes the weak spot. Use shared validation schemas, such as JSON Schema, across all routes.
Vague Errors
A message that says "invalid input" helps nobody. Name the field and the rule.
