160 companion flashcards · AI-assisted study content · Open the deck →
This deck introduces the core concepts behind API testing, starting with the basics of what it is and why it matters, then moving into the different layers of testing — from unit tests to full integration tests. You'll work through key ideas like contracts, happy-path versus negative tests, response shape validation, idempotency, authentication, authorization, and rate limiting. Each card is designed to build a clear mental model of how APIs are tested in practice and what makes a test suite genuinely useful rather than just superficial.
The deck is well suited for software developers who want to write more reliable services, QA engineers who are getting started with API-level testing, and students or job seekers preparing for technical interviews where testing concepts come up. Even if you have some experience with APIs, going through these cards is a good way to make sure your vocabulary and understanding of testing principles are sharp and consistent.
Because many of these concepts only really click when you see them in action, try to connect each card to a real API you've worked with or used — for example, think about where you've seen a 429 status code or a detailed validation error message. When reviewing, space your sessions out over a few days rather than cramming everything at once; the ideas layer on each other, and giving your brain time between sessions helps the terminology around contracts, idempotency, and edge cases move from short-term memory into something you can actually apply.
API testing is the practice of verifying that an application's interfaces behave correctly across functionality, contracts, performance, security, and error handling. It is valuable because it catches defects below the UI layer, runs faster than full end-to-end browser tests, and provides direct confidence in how services actually behave on the wire. Unlike unit tests, which isolate small pieces of logic, and integration tests, which verify components working together, API tests target the service boundary—the HTTP surface that clients actually call. Common categories include functional and contract checks, authentication and authorization checks, validation and error-handling checks, and performance and security tests.
A cornerstone concept is the contract, which describes the expected structure and behavior of requests and responses, including field names, types, and status codes. Good tests validate contracts explicitly: confirming that status codes communicate success or failure correctly, that response shapes contain required fields with the right types, and that error payloads are meaningful. Both happy-path tests—valid input under normal conditions—and negative tests, which probe invalid, unauthorized, malformed, or out-of-range input, are essential. Edge cases such as empty payloads, large inputs, missing fields, and duplicate requests warrant special attention because they are frequent sources of production bugs. A test oracle, such as a schema, a database state, or a business rule, is the source of truth against which outcomes are judged.
Disciplined setup and isolation keep a suite reliable. Data setup creates predictable preconditions, and fixtures provide stable known data that makes tests easier to read and less brittle. Test isolation ensures that no test depends on the execution order or side effects of another, while schema validation against JSON Schema or OpenAPI definitions catches structural drift automatically. Mocking external services reduces flakiness and clarifies failure causes. Because retries happen in real systems, idempotent endpoints reduce duplicate side effects—an important property to test for. Pagination, sorting, and filtering bugs often produce wrong results without obvious crashes, so they deserve coverage. Consumer-driven contract testing lets consumers record the expectations they rely on and providers verify them continuously, so contract drift is caught before it reaches production. Smoke tests provide lightweight post-deployment confirmation that core endpoints are reachable; regression tests ensure previously working behavior still works after code changes. A flaky test, which passes and fails unpredictably due to timing, shared state, or unstable dependencies, is a warning that underlying instability needs diagnosis rather than retries that hide the problem. Over the long term, a valuable suite stays fast, readable, isolated, and closely tied to the behaviors clients actually depend on.
HTTP status codes are the primary vocabulary an API uses to tell clients what happened. The 4xx class signals client errors: the caller did something wrong and must adjust. Within that class, 401 Unauthorized means the request lacks valid credentials and the client should authenticate and retry, while 403 Forbidden means the caller is authenticated but is not permitted to access the resource. The distinction is often summarized as 401 asking "who are you?" and 403 saying "I know who you are, but you cannot have it." 404 Not Found indicates that the resource is not present at the URI and may exist elsewhere or later; 410 Gone goes further, declaring that the resource existed but has been permanently removed.
Two related codes merit careful thought. 400 Bad Request usually signals malformed syntax—invalid JSON, a bad header, or an unreadable payload—whereas 422 Unprocessable Entity indicates that the body is syntactically valid but semantically rejected, typically by business-rule validation. Choosing between them matters: tests should confirm that an API returns 400 for broken payloads and 422 for valid-but-rejected ones, because clients often branch on these codes. 429 Too Many Requests says the client has exceeded a rate limit and should slow down, usually honoring a Retry-After header. 503 Service Unavailable communicates that the server is temporarily unable to handle the request due to overload or maintenance, and is also frequently paired with Retry-After. The 5xx class as a whole signals backend failures the client did not cause, while rate-limit testing in general verifies that the system protects itself from abuse and noisy clients and communicates failures clearly.
Success codes carry their own semantics. 201 Created indicates that a new resource was created and the response should include a Location header pointing to a canonical URI for that resource. 204 No Content signals successful processing with an intentionally empty body—clients must not expect a payload. Two codes tied to caching and concurrency round out the set: 304 Not Modified tells the client to reuse its cached copy, triggered by If-None-Match or If-Modified-Since, and 412 Precondition Failed indicates that a precondition header such as If-Match or If-Unmodified-Since evaluated to false, so the server declines the request. Tests should explicitly assert status codes, because a payload can look reasonable while an incorrect code silently breaks integrations.
An HTTP method is safe if it is intended to be read-only and must not cause side effects: GET and HEAD are the canonical examples. RFC 7231 defines GET, HEAD, PUT, DELETE, and (practically) OPTIONS and TRACE as idempotent—repeated identical calls leave the server in the same observable state. Understanding the difference is crucial because retries in distributed systems depend on it. PUT and DELETE are idempotent even though DELETE may change a 200 to a 404 the second time; what matters is that no additional side effects occur beyond the first successful call. PUT and PATCH are often confused: PUT replaces the entire resource with the submitted representation, while PATCH applies a partial change to specific fields.
Testing PATCH endpoints is harder because the format varies. JSON Merge Patch (application/merge-patch+json) describes changes by including fields to update, setting fields to null to remove them, and omitting fields to leave them untouched, whereas JSON Patch (application/json-patch+json, RFC 6902) describes a sequence of operations such as add, remove, replace, move, copy, and test. Tests for PATCH must carefully cover missing fields, null values, and unknown fields to ensure the server preserves the rest of the resource. For state-changing operations—especially POST—clients can send an Idempotency-Key header so the server can deduplicate retries and avoid duplicate side effects. Request validation at the API layer checks that an incoming request meets the contract—required fields present, types correct, values within allowed ranges, and business rules satisfied—before any business logic runs.
Headers carry much of the metadata HTTP services depend on. The Location header in a 201 response gives clients a canonical URI for the newly created resource. The ETag header carries an opaque token representing a specific resource version, used both for caching (If-None-Match produces 304 Not Modified) and for optimistic concurrency control: if a client sends If-Match with a write request and the resource has changed, the server responds with 412 Precondition Failed. WWW-Authenticate, sent with 401, tells the client which authentication scheme is required and any parameters; Retry-After, paired with 429, 503, and sometimes 3xx, tells the client how long to wait. For errors, RFC 7807 Problem Details (application/problem+json) provides a standardized shape containing at least type, title, status, and detail, with an optional instance URI—a much better format than ad-hoc JSON for telling clients what field failed, why it failed, and how to fix the request. Content negotiation lets clients request representations via Accept, Accept-Language, or Accept-Encoding, and the Vary response header tells caches which request headers the response depends on so caches do not serve the wrong variant to later clients.
Authentication answers "who are you?" while authorization answers "what are you allowed to do?" In practice, an Authorization header such as Bearer <token> proves identity; the server then decides what that identity may access based on roles, scopes, or claims. Authentication testing checks that an API properly identifies the caller using credentials like tokens, sessions, or API keys; authorization testing checks that an authenticated caller is allowed to access a specific resource or perform an action. API key authentication sends a shared secret in a header or query parameter with each request, but its main weakness is that the key is a single long-lived credential—anyone who obtains it can impersonate the caller. Basic authentication simply base64-encodes a username and password on every request and is trivially decoded, while Digest authentication uses a challenge–response hash so the password never travels on the wire.
More robust schemes include Bearer tokens sent in Authorization headers, where possession of the token is sufficient to authenticate the caller, and OAuth 2.0, an authorization framework in which a client obtains a delegated access token from an authorization server and uses it to call a resource server on behalf of a resource owner. OAuth uses short-lived access tokens for calling the API and long-lived refresh tokens only for obtaining new access tokens without prompting the user. JWTs—a compact, signed token format with three base64url-encoded parts (header, payload, signature)—carry their own claims such as sub (subject, the principal identifier) and exp (expiration in Unix seconds). Because JWTs are self-contained, they should generally be signed so receivers can verify the issuer and that the claims were not altered in transit. Mutual TLS (mTLS) takes a different approach, requiring both client and server to present X.509 certificates during the TLS handshake, proving identity at the transport layer.
Browser-based clients face additional concerns. Cross-Site Request Forgery (CSRF) tricks a victim's browser into sending a request with the victim's cookies attached, so APIs relying on session cookies must defend against it with CSRF tokens, SameSite cookies, or custom headers. Cross-Origin Resource Sharing (CORS) governs how browsers allow cross-origin requests: APIs advertise their policy through Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Allow-Credentials, and Access-Control-Max-Age. Notably, Access-Control-Allow-Origin: * is incompatible with credentialed requests—browsers require a specific origin in that case to prevent leaking the user's session to arbitrary sites. API tests should verify both the presence and correctness of these headers because misconfigurations break clients without producing obvious server errors.
REST is an architectural style organized around resources identified by URIs, with a uniform interface, stateless requests, and representations (typically JSON) transferred over HTTP. Its core constraints—client–server separation, statelessness, cacheability, uniform interface, layered system, and optional code-on-demand—come from Fielding's dissertation. RPC, by contrast, models verbs (actions and procedures) rather than nouns and often uses POST against a custom endpoint with method semantics defined by the API itself. RESTful design tends to map naturally to HTTP verbs; RPC tends to encode business operations as named endpoints. Both have their place, and the choice influences how clients and tests are structured.
GraphQL is a query language and runtime that lets clients send a single POST to one endpoint with a query describing exactly which fields they need, and the server returns a JSON response matching that shape. The flexibility introduces a unique testing concern: because one endpoint can resolve many resources, malicious or naive queries can otherwise exfiltrate data or trigger denial of service. Tests should cover query complexity analysis, depth limits, and field-level authorization. A query depth attack nests fields many layers deep (for example user → friends → friends), causing exponential work; defenses include depth limits and cost analysis. A related backend hazard is the N+1 query problem, where a single response triggers one database query per item due to a loop fetching related rows, hurting performance linearly with result size—fixable with eager loading or batched fetchers.
The OWASP API Security Top 10 tracks the most critical API security risks. Broken Object Level Authorization (BOLA) happens when the server fails to verify that the authenticated user may access a specific object ID—GET /orders/123 returning any user's order is the canonical case. Broken Function Level Authorization is the failure to restrict access to privileged endpoints like /admin based on the caller's role. Excessive Data Exposure occurs when an API returns more fields than the consumer needs because the serializer is overly broad, leaking password hashes or PII. Mass Assignment vulnerabilities let attackers set fields they should not control (for example is_admin=true in a profile update) by binding client-supplied fields directly to a model without filtering. Server-Side Request Forgery (SSRF) tricks the server into fetching an unintended URL—often a cloud metadata endpoint like 169.254.169.254, which can leak IAM credentials. SQL injection remains a threat whenever untrusted input is concatenated into queries; testing with payloads like ' OR 1=1-- helps verify defenses. Other defensive testing practices include parameter pollution tests (duplicate query parameters), fuzz testing (random, malformed, or unexpected inputs), boundary value testing at the edges of valid ranges, and equivalence partitioning to keep the test set small but thorough.
In microservice systems, contract testing verifies that a provider service's API still matches the expectations of its consumers—request and response shapes, status codes, and headers. Pact is the most popular consumer-driven contract testing tool: consumers record their expectations as pacts, providers verify against those pacts in CI, and teams can deploy independently with confidence. In Pact terms, the consumer is the service that calls another API and defines the contract, while the provider is the service that exposes the API and must satisfy all consumer pacts. Consumer-driven contract testing yields particular value when many teams consume the same API; it surfaces contract drift early, before mismatched field names or new required parameters reach production.
Test doubles support both contract and integration work. A mock server simulates a real API's responses, allowing client teams to develop against a stable, controllable fake without waiting on the backend. Subtle distinctions exist between mocks and stubs: a stub returns canned responses to specific calls, while a mock also verifies that expectations were met (for example "this method was called once with these args"); in API testing the terms are often used interchangeably. WireMock is a popular open-source library for stubbing and mocking HTTP services with recorded and playback scenarios, and virtualization tools such as Hoverfly and Mountebank capture real HTTP traffic and replay it as a virtual service, letting tests run against a likeness of upstream APIs without hitting the real dependency. Service virtualization more broadly simulates components that are unavailable, slow, or shared—databases, third-party APIs, mainframes—so dependent services can be tested in isolation. Postman Mock Server serves a mock implementation from a saved collection, parallelizing client and server development. Schema-first development takes this discipline further: writing the OpenAPI specification first, then generating server stubs, client SDKs, and tests keeps implementation, docs, and contracts in sync. OpenAPI describes an API as a whole—paths, operations, parameters, security—while JSON Schema describes the shape of a single JSON document; OpenAPI reuses JSON Schema for its request and response bodies.
Test design choices determine a suite's long-term value. The Arrange-Act-Assert pattern structures each test as setup, action, and verification. Given-When-Then (Gherkin) provides a BDD-flavored, behavior-focused equivalent that reads well to non-engineers. JSONPath lets tests assert on deeply nested fields, and libraries like JSONassert and json-schema-validator perform full or partial shape matching. Typed API client libraries, often generated from OpenAPI, make tests more readable and refactor-safe compared to hand-built payloads. Coverage comes in two flavors: code coverage measures executed lines and branches in the implementation, while API coverage measures which endpoints, status codes, and parameter combinations have been exercised at the HTTP boundary. The test pyramid suggests many unit tests at the bottom, a moderate number of integration and API tests in the middle, and a small number of end-to-end tests at the top; the test trophy variation emphasizes static typing and integration tests because they catch more real-world bugs with less maintenance. Shift-left testing runs API tests as early as possible—in CI on every commit, in pre-commit hooks, or locally—catching defects long before production. A CI pipeline check executes the API suite on every commit and pull request, gating merges on green. Integration tests call the API and may exercise the database or one downstream service, while end-to-end tests exercise the full stack including the UI, real third-party APIs, and live infrastructure. The boundary between unit and component API tests is worth defining: unit tests exercise a single function or class, while component tests drive one service end-to-end through its real HTTP surface—routing, validation, persistence—but still stub external services.
Practical infrastructure supports all of the above. Sandbox environments mirror production closely enough to safely run integration and E2E tests without affecting real users or data. Data masking replaces sensitive PII or payment fields with realistic-looking but fake values, and test data seeding loads a known dataset via SQL, factories, or API calls so assertions target predictable values. A factory is a helper that generates valid, randomized test objects so each test gets fresh, isolated data. Common tooling for everyday work includes Postman (a saved collection of requests, variables, tests, and environments), Newman (its command-line runner for headless CI), curl (invaluable for quick probing and bug reproduction), and HTTPie (a more humane command-line client). For methods, prefer curl -d with an explicit Content-Type header over curl -X POST, which forces the method without setting defaults reliably.
Beyond correctness, APIs must remain fast, reliable, and observable under load. Load testing measures behavior under expected and peak load to confirm latency, throughput, and error rates stay within targets. Stress testing pushes beyond capacity to find breaking points and observe how the system fails—gracefully or catastrophically. Soak testing runs moderate load for hours or days to expose slow leaks: memory growth, file handle exhaustion, and connection pool saturation. Spike testing applies sudden short bursts to verify recovery, and breakpoint testing incrementally increases load until the system fails to determine actual maximum capacity rather than a theoretical one. Popular tools include k6, JMeter, Gatling, Locust, and wrk. When evaluating results, percentiles matter more than averages: p50 is the median response time, p95 represents the worst case for 95% of requests, and p99 for 99%—the long tail is where most user pain lives. Performance assertions should be realistic enough to catch regressions without failing simply because environments vary slightly across runs.
Reliability targets translate into SLOs. An SLO (Service Level Objective) is a quantified reliability target such as "99.9% of requests succeed with p99 latency under 300ms over a 30-day window." An SLA (Service Level Agreement) is the contractual, customer-facing commitment that often carries financial consequences if missed. The error budget is the derived allowance for failure (for example, 0.1% downtime per month equals about 43 minutes); once exhausted, the team prioritizes reliability work over new features. A flaky test, which passes and fails unpredictably, signals underlying timing or state problems; retries in tests can mask real instability rather than diagnosing it, so they should be used with care. Observability—the ability to inspect logs, metrics, traces, and responses well enough to debug failures quickly—is what ties performance and reliability to debuggability.
Distributed tracing follows a single request across services, correlating timed spans by a shared trace ID to debug latency and failures end-to-end. A span is a single unit of work, with a name, start and end times, attributes such as http.status_code, and a parent span ID, typically following the OpenTelemetry data model. OpenTelemetry (OTel) is an open standard and SDK set for instrumenting applications to emit traces, metrics, and logs in a vendor-neutral format, often exported via OTLP to backends like Jaeger, Tempo, or Honeycomb. Operations practices complement this picture: a health check endpoint (often /health or /healthz) reports liveness and readiness; liveness asks "is the process alive?" (restart if not) while readiness asks "should I receive traffic?" (remove from the load balancer if not, for example when warming up or dependencies are down). Graceful shutdown drains in-flight requests, refuses new ones, finishes database transactions, and releases resources on SIGTERM, enabling zero-downtime deploys. Release strategies further limit blast radius: blue-green deployment runs the new version alongside the old and switches traffic atomically with the old version kept warm for instant rollback, canary deployment rolls out to a small fraction of traffic first and gradually increases, and feature flagging gates new behavior behind configuration so both old and new paths can be tested and rolled out or rolled back without redeploy.
Retry-After header.If-Match, If-Unmodified-Since) evaluated to false, so the server will not perform the request.SameSite cookies, custom headers).$.user.addresses[0].city), commonly used in API tests to assert on deeply nested fields.Drill this topic
160 flashcards on API Testing — free, no signup needed to start.
Study API Testing flashcardsLearnWiki pages are generated with AI assistance from LearnCoachAssist's reviewed study catalog and may contain errors — verify anything critical against your course materials.