Back to cheat sheets

API & Data

API Testing

HTTP fundamentals, what to validate, test-case design, authentication, schema and contract testing, and C# / Playwright implementation — with rapid-fire Q&A.

Now playing: API Testing

API Testing

Two-host episode · 13:25

0:0013:25
 Download

Now playing: API Testing

API Testing

Mock interview · 7:58

0:007:58
 Download

01Core HTTP

Methods & semantics

  • GET — retrieve, no body, idempotent, cacheable.
  • POST — create, not idempotent (two calls = two resources).
  • PUT — full replace/update, idempotent.
  • PATCH — partial update, not necessarily idempotent.
  • DELETE — remove, idempotent.
Idempotency = the same request made once or many times leaves the server in the same state. Note: idempotent ≠ same response — DELETE twice returns 200 then 404, but the end state is identical.

02Status Codes — Know These Cold

CodeMeaning & when
200OK — successful GET / general success.
201Created — POST succeeded; often returns a Location header.
202Accepted — request queued for async processing.
204No Content — success with empty body (DELETE / PUT).
301/302Permanent / temporary redirect.
304Not Modified — caching / conditional requests.
400Bad Request — malformed syntax / payload.
401Unauthorized — not authenticated (who are you?).
403Forbidden — authenticated but no permission (you can't do this).
404Not Found.
405Method Not Allowed.
409Conflict — e.g. duplicate creation.
422Unprocessable Entity — semantic / validation failure.
429Too Many Requests — rate limited.
500Internal Server Error.
502/503/504Bad Gateway / Service Unavailable / Gateway Timeout.

401 vs 403 is a classic — 401 means the server doesn't know who you are; 403 means it knows you and you're still not allowed.

03What You Actually Validate

For any API response, check beyond just the status line:

  1. Status code — correct for the scenario.
  2. Response body — correct values and correct data types.
  3. Schema — structure matches the contract (JSON Schema: required fields, shape, types).
  4. HeadersContent-Type, auth, caching, rate-limit headers.
  5. Response time — within the SLA.
  6. Side effects — did the POST actually persist? Verify with a follow-up GET.

04Test Case Design

Positive

Valid inputs produce the expected success response and the expected persisted state.

Negative
  • Missing required fields → 400 / 422.
  • Invalid data types or malformed JSON → 400.
  • Missing / invalid / expired auth token → 401.
  • Insufficient permissions → 403.
  • Non-existent resource → 404.
  • Duplicate creation → 409.
  • Boundary values — empty string, max length, zero, negatives, oversized payloads.
Other dimensions

Pagination, filtering / sorting parameters, rate limiting (429), concurrency, and idempotency keys.

05Authentication

  • API Key — static key in a header or query param.
  • Bearer token / JWTAuthorization: Bearer <token>. A JWT is header.payload.signature; the payload carries claims (exp, sub, roles).
  • OAuth 2.0 — token-exchange flow; in tests you typically grab a token via client-credentials or password grant in setup, then reuse it.
  • Basic Auth — base64 user:pass, rarely used now.
Common question: how do you handle token expiry in a suite? → Fetch the token once in a setup / fixture, cache it, and refresh when it expires rather than logging in per test.

06Schema & Contract

JSON Schema validation

Assert the shape — required fields present, correct types, structure intact — not just individual values. More robust and maintainable than field-by-field assertions when the payload is large.

Contract testing (Pact)

Consumer and provider agree on a contract; it catches breaking changes between services without a full integration environment. It's consumer-driven.

Schema validation checks the shape of one response. Contract testing verifies the agreement between two services stays intact.

07API vs UI Testing

  • API tests are faster, more stable, and less flaky — no rendering, no waiting on elements.
  • They exercise business logic and data integrity directly.
  • They sit in the middle of the test pyramid — many fast unit tests at the base, a healthy API/integration layer in the middle, few UI/E2E tests at the top.
  • They catch issues earlier and pinpoint failures more precisely than UI tests.

08Mocking & Test Data

  • Mock / stub external dependencies (WireMock, mock servers) to isolate the service under test and control responses.
  • Setup / teardown — create preconditions via API, clean up after; keep each test independent and idempotent.
  • Environment management — base URLs, secrets, and tokens configured per environment (dev / staging).

09C# Implementation

RestSharp

var client = new RestClient("https://api.example.com");
var request = new RestRequest("/users/1", Method.Get);
request.AddHeader("Authorization", $"Bearer {token}");
var response = await client.ExecuteAsync(request);

Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var user = JsonConvert.DeserializeObject<User>(response.Content);
Assert.That(user.Id, Is.EqualTo(1));

Playwright API testing

var request = await playwright.APIRequest.NewContextAsync(new()
{
    BaseURL = "https://api.example.com",
    ExtraHTTPHeaders = new Dictionary<string, string>
    {
        ["Authorization"] = $"Bearer {token}"
    }
});

var response = await request.GetAsync("/users/1");
Assert.That(response.Status, Is.EqualTo(200));
var body = await response.JsonAsync();
Strong talking point: Playwright's APIRequestContext lets you mix API setup with UI tests in one framework — e.g. create test data via API, then verify it in the UI. Clean way to seed state without clicking through the app.

Suite structure to raise

  • A base / client wrapper class for the HTTP client and auth.
  • POCO models for request / response deserialization.
  • [SetUp] / [OneTimeSetUp] for token acquisition (NUnit), or fixtures (xUnit).
  • Data-driven tests ([TestCase], [TestCaseSource]) for negative cases.
  • Separate config per environment.

10Rapid-Fire Q&A

Reveal each answer to self-check, then test yourself with the quiz.

PUT vs PATCH?

PUT replaces the whole resource (missing fields get reset); PATCH updates only the fields sent. PUT is idempotent; PATCH usually is but not guaranteed.

401 vs 403?

401 = not authenticated, server doesn't know you. 403 = authenticated but not permitted for this resource.

How do you validate a response beyond status code?

Body values & types, schema/structure, headers, response time, and side effects (verify a POST persisted with a follow-up GET).

How do you test an authenticated endpoint?

Acquire a token in setup, attach Authorization: Bearer, reuse/refresh it. Also test no-token → 401, expired → 401, wrong role → 403.

What's idempotency?

A request that, made once or many times, leaves the server in the same state. GET/PUT/DELETE yes, POST no. Refers to state, not response.

How do you handle dynamic / changing response data?

Don't hard-assert volatile fields (IDs, timestamps). Assert type/format or capture generated values at runtime and reuse them; validate format or a range for timestamps.

How do you keep API tests independent?

Each test sets up its own data and cleans up; no shared mutable state, no order dependency; unique/generated data (GUIDs) for safe parallel runs.

Where do API tests fit in the test pyramid?

The middle layer — above unit, below UI — the best balance of coverage, speed, and stability.