Request Schema

Standards Security Notes Jan 9, 2026 JSON
schema validation request api-design input-validation

Definition

A request schema is a formal specification that defines what data clients must send when calling an API endpoint. It describes the structure of request bodies (for POST, PUT, PATCH), query parameters, headers, and path parameters. The schema specifies data types, required fields, validation constraints (like min/max values, string patterns), and often includes examples to guide developers.

Request schemas serve as the first line of defense against bad data. Before your business logic runs, before database queries execute, before expensive computations happen, the API gateway or framework validates incoming requests against the schema. Invalid requests get rejected immediately with clear error messages, protecting backend systems from malformed data and reducing debugging time.

In OpenAPI specifications, request schemas are defined in the requestBody section for body content and in parameters for URL/query/header values. These schemas are both documentation (showing developers what to send) and enforcement (validating actual requests).

Example

User Registration Endpoint: A signup API defines a request schema requiring email (string, email format), password (string, minLength: 12, pattern with complexity rules), username (string, 3-20 alphanumeric characters), and optional referralCode (string, exact 8 uppercase letters). Requests missing email or with weak passwords are rejected before touching the database.

E-commerce Checkout: A checkout endpoint’s request schema requires items (array of objects with productId and quantity), shippingAddress (object with required fields: street, city, zip, country), paymentMethod (enum: credit_card, paypal, bank_transfer), and conditionally requires cardDetails only when paymentMethod is credit_card. The schema ensures all necessary data is present before processing the order.

Search API with Filters: A product search endpoint defines query parameter schemas: q (string, minLength: 2, maxLength: 200), category (enum of valid categories), minPrice and maxPrice (numbers, minimum: 0), page (integer, minimum: 1), sort (enum: price_asc, price_desc, relevance). Requests with invalid parameters (like page: -1 or minPrice: “abc”) are rejected.

File Upload Endpoint: A document upload API’s request schema specifies Content-Type header must be multipart/form-data, file size maximum 10MB, allowed file types (pdf, docx, txt via pattern on filename extension), and requires metadata fields like title and description in the form data.

Batch Operations: A bulk user update endpoint requires an array of user objects in the request body, with schema constraints: array minItems: 1, maxItems: 100 (preventing DOS via huge batches), each user object requiring id (UUID format) and optional fields to update with their own validation rules.

Analogy

The Airport Security Checkpoint: Before you can board (process the request), security (schema validation) checks that your carry-on (request body) meets size limits, contains no prohibited items (invalid data types), and your ID (required fields) is present and valid. Fail the check, and you don’t proceed - you fix the issue and try again.

The Restaurant Order Form: When ordering food, the form (request schema) requires you to select an entree (required field), specify quantity (integer, minimum: 1), optionally add sides (array of valid options), and note allergies (string, maxLength: 200). The kitchen (backend) only receives complete, valid orders - incomplete forms get sent back to you.

The Loan Application: A bank’s loan application (request schema) requires proof of income (required, numeric, minimum: 0), employment history (array of objects with specific fields), credit score (integer, 300-850 range), and loan amount (number, within bank’s lending limits). Applications missing required documents or with out-of-range values are rejected immediately, before underwriters review them.

Code Example


# [OpenAPI 3](https://reference.apios.info/terms/openapi-3/).x Request [Schema](https://reference.apios.info/terms/schema/) Definition
paths:
  /api/users:
    post:
      summary: Create a new user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - email
                - password
                - username
              properties:
                email:
                  type: string
                  format: email
                  description: User's email address
                  example: [email protected]
                password:
                  type: string
                  minLength: 12
                  maxLength: 128
                  pattern: "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]+$"
                  description: Password with uppercase, lowercase, digit, special char
                  example: SecureP@ssw0rd!
                username:
                  type: string
                  minLength: 3
                  maxLength: 20
                  pattern: "^[a-zA-Z0-9_]+$"
                  description: Alphanumeric username with underscores
                  example: alice_smith
                dateOfBirth:
                  type: string
                  format: date
                  description: Birth date (must be 18+ years ago)
                  example: "1995-06-15"
                referralCode:
                  type: string
                  pattern: "^[A-Z]{8}$"
                  description: Optional 8-character uppercase referral code
                  example: WELCOME2024
              additionalProperties: false
      responses:
        '201':
          description: User created successfully
        '400':
          description: Invalid request data
          content:
            application/json:
              schema:
                type: object
                properties:
                  errors:
                    type: array
                    items:
                      type: object
                      properties:
                        field:
                          type: string
                        message:
                          type: string
              example:
                errors:
                  - field: email
                    message: "must be a valid email address"
                  - field: password
                    message: "must contain at least one uppercase letter"

Validating request in Express.js:


const Ajv = require("ajv");
const addFormats = require("ajv-formats");

const ajv = new Ajv({ allErrors: true });
addFormats(ajv);

const createUserSchema = {
  type: "object",
  required: ["email", "password", "username"],
  properties: {
    email: { type: "string", format: "email" },
    password: {
      type: "string",
      minLength: 12,
      maxLength: 128,
      pattern: "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]+$"
    },
    username: {
      type: "string",
      minLength: 3,
      maxLength: 20,
      pattern: "^[a-zA-Z0-9_]+$"
    },
    dateOfBirth: { type: "string", format: "date" },
    referralCode: {
      type: "string",
      pattern: "^[A-Z]{8}$"
    }
  },
  additionalProperties: false
};

const validate = ajv.compile(createUserSchema);

app.post('/api/users', (req, res) => {
  // Validate request body
  const valid = validate(req.body);

  if (!valid) {
    return res.status(400).json({
      errors: validate.errors.map(err => ({
        field: err.instancePath.substring(1), // remove leading /
        message: err.message
      }))
    });
  }

  // Additional business logic validation
  const age = calculateAge(req.body.dateOfBirth);
  if (age < 18) {
    return res.status(400).json({
      errors: [{ field: "dateOfBirth", message: "must be 18 or older" }]
    });
  }

  // Proceed with user creation
  createUser(req.body);
  res.status(201).json({ message: "User created" });
});

function calculateAge(dateString) {
  const birthDate = new Date(dateString);
  const today = new Date();
  let age = today.getFullYear() - birthDate.getFullYear();
  const monthDiff = today.getMonth() - birthDate.getMonth();
  if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
    age--;
  }
  return age;
}

Diagram

sequenceDiagram
    participant Client
    participant Gateway
    participant Schema
    participant Handler
    participant DB

    Client->>Gateway: POST /api/users
{email, password, ...} Gateway->>Schema: Validate request body alt Invalid Request Schema-->>Gateway: Validation errors Gateway-->>Client: 400 Bad Request
Field-level errors else Valid Request Schema-->>Gateway: Valid Gateway->>Handler: Forward request Handler->>Handler: Business logic validation alt Business rules failed Handler-->>Gateway: Business error Gateway-->>Client: 422 Unprocessable Entity else All valid Handler->>DB: Create user DB-->>Handler: User created Handler-->>Gateway: Success Gateway-->>Client: 201 Created end end

Security Notes

SECURITY NOTES

CRITICAL: Request schemas validate input. Enforce strict validation to prevent attacks.

Validation Points:

  • Content-Type: Validate payload format
  • Required fields: Ensure all required fields present
  • Type validation: Validate field types (string, number, etc.)
  • Format validation: Validate email, URI, date formats
  • Range validation: Validate min/max values

Security Benefits:

  • Injection prevention: Schema validation prevents injections
  • Type safety: Enforced types prevent type confusion
  • DoS prevention: Limits on field lengths prevent resource exhaustion
  • Data integrity: Ensure data meets requirements

Common Issues:

  • Accepting unknown fields: Ignore or reject unknown fields
  • Type coercion: Be careful with automatic type conversion
  • Nested validation: Validate nested structures
  • Array limits: Limit array sizes
  • String length: Limit string lengths

Best Practices:

  • Whitelist fields: Only accept known fields
  • Strict validation: Reject if any field invalid
  • Clear errors: Provide clear error messages
  • Document schema: Publish schema documentation
  • Evolve safely: Maintain backward compatibility

Best Practices

  1. Validate early - Reject invalid requests at the API gateway, not in business logic
  2. Be specific - Use format validators (email, uuid, date-time) instead of generic strings
  3. Set boundaries - Define minLength, maxLength, minimum, maximum on all fields
  4. Provide examples - Include realistic examples in schema for each property
  5. Return actionable errors - Map each validation error to the specific field and constraint violated
  6. Use enums for fixed values - Don’t accept arbitrary strings when a fixed set of values is valid
  7. Validate deeply - Check nested objects and arrays, not just top-level fields
  8. Consider optional fields carefully - Make fields required unless there’s a clear reason for optionality

Common Mistakes

Missing additionalProperties: false: Allowing clients to send arbitrary extra fields creates mass assignment vulnerabilities and makes future schema changes risky.

Weak pattern validation: Using pattern: “.*” or overly permissive regex that accepts invalid data. Be strict upfront.

No size limits: Accepting unbounded strings or arrays enables DOS attacks via huge payloads. Always set maxLength and maxItems.

Validating too late: Running validation after business logic starts, wasting resources on invalid requests. Validate at the edge.

Generic error messages: Returning “validation failed” instead of field-specific errors. Developers need to know exactly what’s wrong to fix it.

Not validating query parameters: Only validating request bodies while ignoring query string injection risks. Schema-validate all inputs.

Inconsistent validation: Having different validation rules in schema vs. business logic vs. database constraints. Schema should be the source of truth.

Standards & RFCs