|

Beyond 200 OK: What Senior QA Engineers Actually Validate in API Testing

Your API returned 200 OK. Your test passed. But the response contained wrong data, missing fields, incorrect calculations, and stale cached results. A 200 status code is not a successful test — it is the beginning of one.

Contents

Real Bugs Hidden Behind 200 OK

  • Wrong data in body: API returns user ID 42’s data when you requested user ID 43
  • Missing fields: The email field is gone after a backend refactor — but status is still 200
  • Incorrect calculations: Order total shows $100 instead of $90 after a 10% discount
  • Stale cached responses: You updated the product price, but the API returns the old price from cache
  • Wrong data types: Price returns as string “29.99” instead of number 29.99

The Senior QA Validation Checklist

  1. Status code — yes, check it, but it is layer 1 of 7
  2. Response body structure — all expected fields present, no extra fields leaked
  3. Data types — numbers are numbers, dates are ISO format, booleans are booleans
  4. Business logic — calculations correct, state transitions valid, relationships consistent
  5. Schema validation — response matches the API contract (JSON Schema)
  6. Security — no sensitive data in response, auth tokens required, rate limiting active
  7. Performance — response time within SLA, no N+1 query indicators

Code: Comprehensive API Validation

test('validate user API response comprehensively', async ({ request }) => {
  const response = await request.get('/api/users/1');
  
  // Layer 1: Status
  expect(response.status()).toBe(200);
  
  // Layer 2: Structure
  const user = await response.json();
  expect(user).toHaveProperty('id');
  expect(user).toHaveProperty('name');
  expect(user).toHaveProperty('email');
  expect(user).not.toHaveProperty('password'); // Security: no leaked fields
  
  // Layer 3: Data types
  expect(typeof user.id).toBe('number');
  expect(typeof user.name).toBe('string');
  expect(user.email).toMatch(/^[^@]+@[^@]+\.[^@]+$/);
  
  // Layer 4: Business logic
  expect(user.id).toBe(1);
  expect(user.name.length).toBeGreaterThan(0);
  
  // Layer 5: Performance
  const timing = response.headers()['x-response-time'];
  if (timing) expect(parseInt(timing)).toBeLessThan(500);
});

JSON Schema Validation

import Ajv from 'ajv';

const userSchema = {
  type: 'object',
  required: ['id', 'name', 'email', 'createdAt'],
  properties: {
    id: { type: 'number' },
    name: { type: 'string', minLength: 1 },
    email: { type: 'string', format: 'email' },
    createdAt: { type: 'string', format: 'date-time' },
  },
  additionalProperties: false // Reject unexpected fields
};

test('response matches JSON schema', async ({ request }) => {
  const response = await request.get('/api/users/1');
  const data = await response.json();
  
  const ajv = new Ajv({ allErrors: true });
  const validate = ajv.compile(userSchema);
  const valid = validate(data);
  
  expect(valid).toBe(true);
  if (!valid) console.log(validate.errors);
});

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.