What is API testing?
API testing is a testing approach that sends requests directly to an application programming interface (API) and checks the responses, without a user interface. A test sends a request to the running software and compares the response with expected values. Those values usually include the status code, the returned data, and the error for bad input.
The International Software Testing Qualifications Board (ISTQB) defines API testing as a test approach that submits requests to a test object through its application programming interface. The ISTQB defines graphical user interface (GUI) testing the same way, through the GUI instead of the API. Both terms name the surface a test acts through, not how much of the system it covers.
For a web app, the API is usually a set of HTTP endpoints that the app's own pages call, e.g. GET /api/orders/A-1042. An API test reaches the same business rules as those pages without starting a browser. Among the levels of software testing, an API test can be an integration test or, when it follows a whole business flow, an end-to-end test.
How does API testing work?
An automated API test usually runs in six steps:
- The test runner, e.g. pytest with an HTTP client, points the test at a running copy of the software.
- The test sets up known data and signs in as a test account.
- The test builds a request from a method, a path, headers, and a body.
- The test sends the request with the account's token or session cookie.
- The test compares the response with expected values.
- The test sends a second request, e.g. a
GET, to read back the stored result.
A useful API test checks more than the status code:
- Status code. The test checks the exact code that RFC 9110, the standard for HTTP semantics, defines for the outcome, e.g. 201 after a request creates an order.
- Response body. The returned data has the expected fields and values, e.g. an order total of $240.00.
- Errors. Invalid input gets a 4xx code and a clear message, e.g. 400 for a missing address, not a 500.
- Stored state. A write changes only what it should, which a second request reads back.
- Access. A request with no credentials gets 401, and a request for another account's data gets 403 or 404. RFC 9110 allows a 404 that hides whether the data exists.
- Repeats. Where an operation needs idempotency, two identical requests leave the same stored state as one. RFC 9110 defines
PUTandDELETEas idempotent andPOSTas not, so a retriedPOSTcan create a second order.
What is an example of an API test?
Here is an illustrative example. Acme Co. sells furniture online, and its checkout page saves changes through the store's API. A developer asks a coding agent to "Let customers edit their delivery address during checkout." The agent adds the endpoint PATCH /api/carts/{id}/address and a test that checks for status 200. That test passes.
A reviewer writes a second API test from the developer's request, with Playwright's built-in request fixture. The fixture sends HTTP requests from Node.js without loading a page. The project's config sets baseURL to https://shop.example.com, and a setup step creates cart C-2210 with 2 items:
import { test, expect } from "@playwright/test";
test("changing the address keeps the cart items", async ({ request }) => {
const res = await request.patch("/api/carts/C-2210/address", {
data: { address: "12 Elm Street" },
});
expect(res.status()).toBe(200);
const cart = await (await request.get("/api/carts/C-2210")).json();
expect(cart.address).toBe("12 Elm Street");
expect(cart.items).toHaveLength(2);
});
The status check and the address check pass. The last line fails:
Error: expect(received).toHaveLength(expected)
Expected length: 2
Received length: 0
Received array: []
The address saved, but the cart emptied. The handler read the request body as a whole cart, so the missing items field defaulted to an empty list and replaced the saved items. The agent changes the handler to update only the address field, and the same test passes.
This example is simplified. A real project would add tests for bad input, e.g. an empty address, and for a customer who does not own the cart.
What changes when a coding agent writes the code?
A coding agent often checks an endpoint it added with one request, e.g. with curl, and reports "done" when the status is 200. A 200 says only that the server reported success. When the agent runs its tests, an exit code of 0 says only that no test failed.
An agent's tests usually check the fields its code sets, because code and test come from the same prompt. An endpoint that returns any order to anyone with an account is one of the common bugs in AI-generated code. A test with one account cannot show it.
An agent can replace the HTTP client with a test double, so its "API test" never reaches a server. A test that skips the status check can pass on a 500, because Playwright's request fixture returns the response for any status code by default. The failOnStatusCode option makes it throw on a 4xx or 5xx code.
A practical adjustment is to write a few API tests from the developer's request before the agent starts. Each write gets a read back, and each endpoint gets one invalid input and one request from a second account. They run on each pull request, e.g. in GitHub Actions.
What are the limits of API testing?
API testing checks the software below its interface, which sets these limits:
- The interface goes untested. A page can drop the address before it sends the request. The API tests still pass while the customer sees a broken checkout.
- Only the written inputs are sent. An endpoint accepts far more inputs than a suite sends. Fuzzing sends large numbers of generated or malformed inputs to find crashes the written tests miss.
- The test checks the copy it runs against. A test against a local server, or against a stub of an outside service, says little about production settings, e.g. a missing environment variable.
- One request at a time says nothing about load. A functional API test sends requests one by one, so it cannot show how the API behaves under heavy traffic, which load testing checks.
- A passing access check is not a security review. A two-account test shows that the requests it sent were refused, not that no other request gets through.
A passing suite is not the same as complete coverage.
How is API testing different from UI testing?
User interface (UI) testing acts through the screens a person uses, usually by clicking and typing in a browser, and checks what the page shows. API testing skips the browser and the page. API tests usually run faster, fail less often for timing reasons, and point closer to the broken rule. UI tests catch what API tests cannot, e.g. a page that sends the address to the wrong endpoint.
Many teams check business rules with API tests and keep a few browser tests for the journeys customers depend on. UI tests often use the API for setup, e.g. to create a cart before the browser opens. The comparison of integration and end-to-end tests shows what each test level runs and what it misses.
How is API testing different from contract testing?
Contract testing checks that two services agree on the requests and responses they exchange, without running both services together. An API test sends real requests to a running API and checks what the API does with them. A contract test usually checks the shape of each message, e.g. field names and types, so a wrong order total of the right type can pass. Teams often use both, with API tests for behavior and contract tests for the agreement between services that ship separately.
FAQs
Can Playwright test an API?
Playwright can test an API through its built-in request fixture, which sends HTTP requests from Node.js without loading a page. A test can check the status and the returned data, and it can mix API calls with browser steps, e.g. to create a cart before the page opens.
What should an API test check besides the status code?
An API test should check the returned data, the error for invalid input, and the stored result, which a second request reads back. For endpoints that need an account, the test should also check that a request with no credentials, or from another account, is refused.
How do you test an API that requires authentication?
You test an API that requires authentication by signing in as a test account and sending its token or session cookie with each request. Other tests send no credentials and expect 401, or use a second account and expect 403 or 404.
Can API tests replace end-to-end tests?
API tests cannot replace end-to-end tests of a web app, because they skip the pages a customer uses. They can take over many checks of business rules from slower browser tests, which leaves a few end-to-end tests for the journeys customers depend on.