Validating Inputs in a REST API
What is Input Validation?
Section titled “What is Input Validation?”- Input validation is the process of verifying that client-provided data meets expected formats, types, and constraints before processing it.
- Without validation, REST APIs are vulnerable to security threats (e.g., SQL injection, command injection) and broken functionality.
- The goal is to ensure that incoming requests (e.g., JSON payloads, query parameters) are secure and work as expected.
- Example:
- Valid:
{"user_id": 123, "name": "Quacker"} - Invalid:
{"user_id": "abc", "name": "##123@@"}
- Valid:
- Example:
Why Input Validation Matters
Section titled “Why Input Validation Matters”- Security: Protects against malicious data and injection attacks (e.g., SQL injection, command injection).
- Data integrity: Ensures inputs match expected types, formats, and constraints (e.g., valid email addresses, positive numbers).
- User experience: Provides clear error messages to API consumers when inputs are invalid.
- Reliability: Prevents crashes, runtime errors, and unexpected behavior from malformed data.
What to Validate?
Section titled “What to Validate?”Input Sources
Section titled “Input Sources”For a REST API, inputs can be provided by the client request in the following ways:
- Query string parameters (e.g.,
GET /species?limit=10) - URL path parameters (e.g.,
GET /players/123) - Request body (e.g., JSON in a POST, PUT, or PATCH request)
- Request headers (e.g.,
Accept,Authorization)
Typical Validation Rules
Section titled “Typical Validation Rules”When processing user or client-provided data in a REST API, you’ll need to validate:
- Presence: Is a required field provided?
- Type: Is the input an integer, string, boolean, etc.?
- Format: Does it match a pattern (e.g., UUID for resource IDs, ISO 8601 for timestamps, valid enum values for status fields)?
- Range/Length: Is it within acceptable bounds (e.g., pagination limit 1-100, offset >= 0, price > 0)?
- Business rules: Does it make sense in your domain (e.g., stock quantity available, valid status transitions)?
How to Validate Inputs in PHP?
Section titled “How to Validate Inputs in PHP?”There are two main approaches to validating inputs in PHP:
- Native PHP functions:
filter_var()for sanitizing and validating common types (e.g., email, URL).isset(),empty()for checking presence.- Type casting/checking with
is_int(),is_string(), etc. - Example:
$email = 'test@example.com';if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {echo 'Invalid email format';}php
- Third-party libraries: Valitron ↗: A simple, stand-alone validation library with no dependencies.
Resources:
Handling Validation Errors
Section titled “Handling Validation Errors”- HTTP Status: Use
400 Bad Requestfor validation failures. - Error Format: Return structured JSON with details.
- Example Response:
{"status": "error","message": "Invalid input","details": [{"field": "age", "message": "must be a positive number"},{"field": "email", "message": "invalid format"}]}json
- Best Practice: Be specific but avoid leaking internal details.
Example Implementation
Section titled “Example Implementation”- Inputs validation scenario:
POST /playersto create a player. - Validation Rules:
name: String, 2-50 chars, required.age: Integer, 18-110, optional.
- Code Example (PHP):
$data = json_decode(file_get_contents('php://input'), true);$errors = [];// Validate nameif (!isset($data['name']) || empty($data['name'])) {$errors[] = ['field' => 'name', 'message' => 'name is required'];} elseif (strlen($data['name']) < 2 || strlen($data['name']) > 50) {$errors[] = ['field' => 'name', 'message' => 'name must be between 2 and 50 characters'];}// Validate age (optional)if (isset($data['age']) && (!is_numeric($data['age']) || $data['age'] < 18 || $data['age'] > 110)) {$errors[] = ['field' => 'age', 'message' => 'age must be an integer between 18 and 110'];}if (!empty($errors)) {http_response_code(400);echo json_encode(['status' => 'error', 'message' => 'Validation failed', 'details' => $errors]);exit;}php
Input Validation Checklist
Section titled “Input Validation Checklist”- Validate early: Check inputs at the controller or service layer.
- Use schemas: Define strict data models (e.g., JSON Schema, OpenAPI).
- Sanitize inputs: Remove or escape unsafe characters. Even after validation, use
filter_var()or similar to sanitize before database insertion. - Enforce types: Reject mismatched types (e.g., string instead of integer).
- Set boundaries: Limit lengths, ranges, and allowed values.
- Example:
"age": { "type": "integer", "minimum": 0, "maximum": 150 }
- Example:
- Use HTTP Status Codes:
- 400: Bad Request (malformed JSON).
- 422: Unprocessable Entity (validation errors).
- Centralize Validation:
- Move rules and messages to a separate class or helper class for reusability.
- Log Errors:
- Log validation failures for debugging or security monitoring.
- Document Your API:
- Use OpenAPI/Swagger to specify expected inputs and error responses.
- Handle Edge Cases:
- Test with empty strings, null values, malformed JSON, and oversized payloads.