Microservices & Event-Driven Testing

End-to-End API Testing (Microservices)

Rishi GauravUpdated Oct 19, 202616 min read

Quick answer

End-to-end API testing checks a complete business flow through the API layer: log in, create the order, pay and read back the final state, passing tokens and IDs between calls across every service. It skips the UI, so it is faster and steadier than browser tests. Keep it to a few critical journeys and stub third-party APIs.

Reviewed by Sushant Joshi

Share:
End-to-end API testing for microservices showing a user journey across services, test environments and the CI/CD pipeline

Part of the Microservices & Event-Driven Testing hub. Start with the pillar guide: Microservices testing: strategy, types and tools.

End-to-end API testing validates a complete business flow through the API layer — log in, create the order, pay, confirm — by calling each service's API in order, passing tokens and IDs from one response to the next request, and asserting the final state everywhere it should have changed. It is the top layer of the strategy in our microservices testing guide, and in a microservices system it is the cheapest way to prove that independently deployed services still add up to a working product.

A ride-sharing team had 150 microservices, 12,000 unit tests and 800 contract tests, all green. Then ride requests started failing silently: the app sat on "searching for drivers" forever. The matching service now expected a field in the location payload that the mobile gateway did not send, and the contract had not been updated because everyone assumed the field was optional. Four hours of investigation later, one end-to-end API test of "request a ride" would have caught it before release.

Unit tests prove components. Contract tests prove pairs of services agree. Only an end-to-end test proves the journey. The catch is cost: end-to-end suites are slow, flaky and expensive when they try to cover everything. This guide shows how to keep them small, fast and trustworthy.


In this guide

  1. What is end-to-end API testing?
  2. Why end-to-end testing is hard in microservices
  3. How to do end-to-end API testing, step by step
  4. Environments, service virtualization and test data
  5. End-to-end API testing frameworks and tools
  6. Worked example: an e-commerce checkout
  7. End-to-end API testing challenges and best practices
  8. End-to-end API testing FAQ

What is end-to-end API testing?

A typical end-to-end API test:

  1. Authenticates and keeps the token.
  2. Calls the entry-point API (usually through the gateway) to start the journey.
  3. Lets the request flow through authentication, business services, databases, caches and queues.
  4. Calls the next API in the journey with values captured from earlier responses (order ID, cart ID, payment ID).
  5. Waits for any asynchronous step to finish.
  6. Asserts the final response and the side effects: database records, emitted events, emails, external calls.

It differs from its neighbours like this:

Test typeScopeSpeedStabilityWhat it proves
UnitOne function or classMillisecondsVery stableLogic
API (per service)One service's endpoints, dependencies mockedSecondsStableThe service's contract and behaviour
ContractOne consumer-provider pairSecondsStableThe pair still agrees
End-to-end APIA whole journey through the APIsSeconds to minutesModerateThe services add up to a working flow
UI end-to-endA whole journey through the browserMinutesFragileThe user can complete it in the product

End-to-end API tests keep most of the confidence of UI end-to-end tests with far less flakiness, because there is no rendering, selectors or browser timing. Most teams run a handful of UI journeys on top for the front end and do the rest through the API. Where the line sits between the two is worked through in end-to-end testing vs API testing.


Why end-to-end testing is hard in microservices

  • Environment complexity. A journey through eight services needs eight services running, healthy and configured, each with its own data store.
  • Asynchronous steps. Messages on Kafka, webhook callbacks and queued emails mean the final state appears later than the response. Polling is mandatory; see event-driven API testing.
  • Test data across services. Users, products, inventory and payment methods must exist in several databases, uniquely per run.
  • Flakiness. Startup order, network timeouts, slow consumers and shared data all produce false failures.
  • Maintenance. A change in any of the eight services can break the test, even when it is backward compatible.

None of these is a reason to skip end-to-end testing — they are reasons to keep the suite small and invest in the infrastructure around it.


How to do end-to-end API testing, step by step

1. Choose the journeys

List the flows where an integration failure would hurt most: checkout, sign-up, payment, a ride request. Pick five to ten. For each, include the most important error path (out of stock, payment declined). That is the whole end-to-end suite; everything else belongs in per-service API and contract tests.

2. Write the call chain

Write down every API call in order, what each one needs from earlier responses, and what the end state must be. This is the test design; the code follows from it.

3. Chain the calls and capture values

Here is the checkout journey as a k6 script. k6 is useful because the same script can later run under load:

import http from 'k6/http';
import { check, group, sleep } from 'k6';

const BASE = 'https://staging.api.example.com';
const json = { 'Content-Type': 'application/json' };

export default function () {
  let token, orderId;

  group('1. Authenticate', () => {
    const r = http.post(`${BASE}/auth/login`,
      JSON.stringify({ email: __ENV.TEST_USER, password: __ENV.TEST_PASSWORD }), { headers: json });
    check(r, { 'login 200': (res) => res.status === 200 });
    token = r.json('token');
  });

  const auth = { ...json, Authorization: `Bearer ${token}` };

  group('2. Create order', () => {
    const r = http.post(`${BASE}/orders`,
      JSON.stringify({ items: [{ productId: 'PROD-001', quantity: 2 }] }), { headers: auth });
    check(r, { 'order 201': (res) => res.status === 201, 'has id': (res) => !!res.json('orderId') });
    orderId = r.json('orderId');
  });

  group('3. Wait for async confirmation', () => {
    let status = 'pending';
    for (let i = 0; i < 10 && status === 'pending'; i++) {
      sleep(2);
      status = http.get(`${BASE}/orders/${orderId}/status`, { headers: auth }).json('status');
    }
    check(status, { 'order confirmed': (s) => s === 'confirmed' });
  });

  group('4. Verify side effects', () => {
    const inv = http.get(`${BASE}/inventory/PROD-001`, { headers: auth });
    check(inv, { 'stock reserved': (res) => res.json('reserved') >= 2 });
  });
}

Ready to shift left with your API testing?

Try our no-code API test automation platform free. Generate tests from OpenAPI, run in CI/CD, and scale quality.

Credentials come from environment variables, the order ID is captured once and reused, and the async step polls with a cap instead of sleeping a fixed time.

4. Assert the end state in every service

Do not stop at "the last call returned 200". Check what each service should have done: the order is confirmed, stock is reserved, the payment is captured, the confirmation event was published. A green final response with a missing side effect is the bug end-to-end tests exist to find.

5. Seed and clean up

Create unique data at the start of each run (a new user, a new cart) and delete it at the end, so parallel runs and reruns never collide.

6. Run it in CI, then in production

Run a smoke subset on pull requests that cross service boundaries, the full suite on merges to main, an extended suite nightly — and the happy path as a synthetic transaction against staging or production every few minutes, alerting when it fails or exceeds its latency target.

Building the chain without glue code

Much of the cost is the glue: deciding the steps and threading the token and IDs through. In Shift-Left API, end-to-end workflows can be built three ways — from an approved use-case requirement with ordered steps, from your specs and existing tests, or from one sentence such as "log in, add two items to the cart, place the order, confirm payment" — and each step's data is wired to the earlier step that produces it. If a step has no matching test or endpoint, it says which and can generate the missing tests. Workflows can span projects, so each step runs against its own team's environment; a workflow can iterate over a data set of customers or carts; and a passing run can verify the requirement it was built from, so the journey shows up in the traceability matrix rather than only in a CI log.


Environments, service virtualization and test data

Environments

ApproachGood forWatch out for
Docker ComposeLocal runs and fewer than ~10 servicesDrifts from production configuration
Ephemeral Kubernetes namespace per runIsolation at any scaleSpin-up time and cost
Shared stagingNightly suites, simple setupState contamination between runs
HybridDeploy only the changed service; virtualize unchanged dependenciesMocks must follow the real contracts

Whatever you choose, gate the run on health: do not start until every service's readiness probe passes. Running the suite inside the cluster is covered in API testing in Kubernetes.

Service virtualization

Replace a dependency with a simulated one when it is a third-party API (payment gateway, shipping, email), a service another team owns that is not in your environment, rate-limited or paid per call, or when you need its error responses on demand (decline, timeout, 500). WireMock and Hoverfly are the common tools; a mock generated from the provider's OpenAPI spec keeps the stub close to the contract. Shift-Left API's mock server generates mocks from imported specs, with conditional responses, fixed delays and error statuses. The technique itself is covered in what is API mocking.

Test data

  • Seed on setup, clean on teardown — the default for isolated environments.
  • Data factories — generate unique users and orders per run (UUID-based) so parallel runs never collide.
  • Dedicated test accounts — simplest, but tests start depending on each other's state.

Cross-service data is the hardest part of end-to-end testing; test data management best practices covers seeding, masking and synthetic data across services.


End-to-end API testing frameworks and tools

ToolTypeBest for
REST AssuredCode-first (Java)Fluent API chains in JVM test suites
pytest + requests/httpxCode-first (Python)Readable chained tests with fixtures for setup and teardown
Playwright request contextCode-first (JS/TS)API journeys next to UI tests in one framework
k6Scripted API journeysJourneys that also need to run under load
Postman + NewmanCollectionsTeams already in Postman; chaining via variables and scripts
KarateDSLGherkin-style API flows without much code
Shift-Left APISpec-driven platformWorkflows built from specs, tests or a sentence, with data wired between steps
WireMock / HoverflyService virtualizationStubbing third parties and unavailable services
Testcontainers / Tilt / SkaffoldEnvironmentsRunning real dependencies or whole stacks for tests
Jaeger / OpenTelemetryObservabilityFinding which hop failed

In Postman, end-to-end testing means one folder per journey, test scripts that save values from each response into variables, and Newman in CI. It works well for a few journeys; beyond that, the chaining logic scattered across scripts becomes the maintenance problem.


Worked example: an e-commerce checkout

The platform chooses three end-to-end API scenarios.

Scenario 1: happy-path checkout

  1. Authenticate (auth service)
  2. Add items to the cart (cart service)
  3. Apply a discount code (promotion service)
  4. Submit the order (order service: create order, reserve stock, start payment)
  5. Confirm payment (payment service)
  6. Check the confirmation email was queued (notification service)
  7. Assert: order "confirmed", stock decremented, payment captured, email queued

Scenario 2: out of stock Submit an order when stock is zero; assert the order service returns the documented error, no payment was started and stock is unchanged.

Scenario 3: payment declined The virtualized payment gateway returns a decline; assert the order is "payment-failed", the stock reservation is released, and the customer can retry.

Setup: each run deploys the six services to an ephemeral namespace, with WireMock standing in for the payment gateway. Data is seeded through the APIs in setup and the namespace is torn down afterwards.

Free Visual blueprint + guide

Microservices Testing Strategy Blueprint

A visual testing strategy for microservices architectures. Covers testing layers, contract testing, service mesh validation, and tool selection.

Download Free

CI/CD: the three scenarios run on every merge to main; a nightly run adds edge cases; Scenario 1 runs as a synthetic transaction against staging every 10 minutes.


End-to-end API testing challenges and best practices

ChallengeImpactSolution
Slow runsLong feedback loopsParallelize independent journeys; full suite on main, smoke on PRs
Environment spin-upMinutes before the first callPre-built images, cached layers, deploy only changed services
Flaky async assertionsRandom red buildsPoll with a cap; health-check gates before the run
Shared test dataTests contaminate each otherUnique data per run; ephemeral databases
Third-party downtimeFailures you cannot fixVirtualize every external dependency
Finding the broken serviceLong investigationsTrace IDs on every test request; one trace per journey
CostCloud bills for environmentsEphemeral only for critical paths; aggressive teardown

Tracing tells you where a run failed, not whether it is worth a developer's afternoon. Shift-Left API's failed-run analysis groups a failed run into a handful of causes, each marked as an environment problem, data issue, test defect or suspected product bug based on what the services actually returned — so a namespace that was not ready, a gateway error page or an expired sign-in is separated from a genuine order-service regression, which is much of what gets labelled "flaky E2E".

Best practices

  • Test only critical flows end to end — five to ten journeys, plus their key error paths.
  • Go through the API, not the browser, unless the UI itself is what you are testing.
  • Assert side effects in every service, not just the final response.
  • Poll, never sleep, and cap every wait.
  • Gate on health before the first request.
  • Virtualize third parties; they are the most common source of flakiness.
  • Put a trace ID on every request so a failure points straight at the hop.
  • Retry once, then report, and track retry rates to find tests that need fixing rather than retrying.
  • Clean up aggressively — stale data and orphaned environments cause both cost and flakiness.

End-to-end API testing checklist

  • ✔ Five to ten critical journeys identified, each with its key error path
  • ✔ Call chain written down with the values each step needs
  • ✔ Tokens and IDs captured from responses, never hard-coded
  • ✔ Async steps polled with a timeout
  • ✔ Side effects asserted in every affected service
  • ✔ Unique data seeded per run and cleaned up afterwards
  • ✔ Third-party dependencies virtualized
  • ✔ Ephemeral or isolated environment with health-check gates
  • ✔ Smoke subset on PRs, full suite on main, extended suite nightly
  • ✔ Happy path running as a synthetic transaction with alerting
  • ✔ Trace links attached to every failed run

Related reading: API Integration Testing: Strategies, Example and CI Setup

End-to-end API testing FAQ

What is end-to-end API testing?

End-to-end API testing validates a complete business flow through the API layer instead of the UI. A test logs in, performs each step of the journey (create, update, pay, confirm) by calling the APIs in order, passes tokens and IDs from one response to the next request, and asserts the final state and side effects across every service involved.

How do you do end-to-end API testing?

Pick one critical journey, list its API calls in order, and write a test that runs them in sequence, extracting values such as the token and order ID from each response. Seed unique data first, poll for asynchronous steps instead of sleeping, stub third-party APIs, assert the end state in every affected service, and clean up afterwards. Then run it in CI on merges to main.

What is the difference between API testing and end-to-end testing?

API testing usually checks one endpoint or one service at a time: status codes, schemas, errors and edge cases. End-to-end testing checks a whole user journey across many services. End-to-end API testing sits between them: it covers the full journey but through the APIs, without a browser, which makes it faster and less flaky than UI end-to-end tests.

What is a good end-to-end API testing framework?

Code-first teams use REST Assured (Java), pytest with requests or httpx (Python), Playwright's request context or Supertest (JavaScript) and k6 when they also want load. Collection-based teams chain requests in Postman and run them with Newman. Spec-driven platforms build the chained workflow from the OpenAPI spec and existing tests.

Can you do end-to-end API testing with Postman?

Yes. Put the journey's requests in one collection folder in order, save values from each response into environment variables with test scripts, use them in later requests, and run the folder with the Collection Runner or Newman in CI. Large suites become hard to maintain because the chaining lives in scripts.

How many end-to-end tests should microservices have?

Keep end-to-end tests to roughly 5-10% of the suite: the five to ten business flows where an integration failure would hurt most, plus their key error paths. Push everything else down to per-service API tests and contract tests, which are faster and pinpoint the broken service.


Sources and further reading

Key takeaways

  • End-to-end API testing proves that independently deployed services still add up to working journeys — the one thing unit and contract tests cannot prove.
  • Test through the API: you keep most of the confidence of UI end-to-end tests with far less flakiness.
  • Keep the suite small — five to ten critical journeys and their key error paths — and push everything else down the pyramid.
  • The infrastructure decides reliability: health gates, unique data, virtualized third parties, polling and trace IDs.
  • Run a smoke subset on PRs, the full suite on main, and the happy path as a synthetic transaction in production.

Ready to build your first journey? Start a free trial and describe it in one sentence: Shift-Left API assembles the workflow from your specs and tests, wires the data between steps and runs it in CI.


Related Articles: Microservices Testing | End-to-End Testing vs API Testing | Contract Testing for Microservices | Event-Driven API Testing | Canary Testing in Microservices Deployments

Continue learning

Go deeper in the Learning Center

Hands-on lessons with runnable code against our live sandbox.

Ready to shift left with your API testing?

Import your OpenAPI spec and get a runnable test suite, in our cloud or on your own infrastructure.