API testing explained: types, what to automate, and tools
API testing checks an interface directly, below the UI. Learn the five main types, how mocking and test data fit in, and which tests to automate first.

API testing means sending requests straight to an application's interface and checking the responses, without going through the user interface. It is faster and more stable than browser testing and it catches most logic bugs before a screen ever shows them. Start by automating the functional checks on your most important endpoints, then add contract, integration, load and security tests as the product grows.
Why test at the API layer
The API is where business rules live. A UI test that clicks through five screens to confirm a discount was applied is slow and breaks when a button moves. An API test sends one request and checks the price.
| Aspect | UI test | API test |
|---|---|---|
| Speed | Seconds to minutes | Milliseconds to seconds |
| Fails because | A button moved, a page was slow, or the logic broke | The logic broke |
| Reach | Only what the screen exposes | Bad input, missing permissions, odd sequences |
| Fits in every pull request | Rarely | Yes |
This holds for a REST API, a GraphQL endpoint or an internal service call. The protocol changes how you build requests, not why you test.
The five main types
| Type | Question it answers | Run it |
|---|---|---|
| Functional | Does this endpoint do what it should? | Every pull request |
| Contract | Do provider and consumers agree on the shape? | Every pull request |
| Integration | Does it work with the real database and queue? | On merge |
| Load | How does it behave under traffic? | Before launch, after query changes |
| Security | How does it fail under hostile input? | On a schedule, before releases |
Functional tests
For each endpoint, check the happy path and the failures:
- The status code and response body for valid input.
- Validation errors for missing, malformed or out-of-range fields.
- Authentication and authorization: a missing token returns 401, a valid token without permission returns 403.
- Edge cases, such as empty lists, very long strings and duplicate submissions.
Assert on the parts of the response that matter. Over-specified assertions make tests brittle.
Contract tests
A contract test checks that a provider and its consumers agree on field names, types, required fields and status codes. It is most valuable when different teams own the two sides, or when a mobile app talks to a backend that ships on a different schedule. In a microservices setup, contract tests catch a breaking change in one service before it breaks another.
Provider-driven contracts validate the API against its published specification, such as an OpenAPI document. Consumer-driven contracts let each consumer record what it relies on, and the provider's build verifies it still holds.
Integration tests
Integration tests run the API against its real collaborators: the database, the cache, a message queue. Use a disposable environment, such as containers started for the test run, so each run begins from a known state. Focus on the seams where things break: queries, transactions, serialization and migrations.
Load tests
Load tests measure response times, error rates and the point where the service starts to degrade. Define what you are measuring first, for example 95th percentile latency at an expected request rate, and test against an environment that resembles production.
Security tests
Start with the common API weaknesses OWASP publishes:
- Broken object-level authorization: can user A read user B's record by changing an ID?
- Weak authentication and missing rate limits.
- Excessive data exposure and injection through query parameters or bodies.
Automated scanners help, but authorization bugs are logic bugs, and they are best caught by tests you write for your own rules.
Mocking and test data
Mocking replaces a dependency with a controlled stand-in. Use it when the real thing is slow, costly, unavailable or hard to push into a failure state. A mock of a payment provider lets you test what your code does when the provider times out or returns a decline, which is hard to trigger on demand with the real service.
Test data decides whether your suite is trustworthy or flaky:
- Create the data each test needs and clean it up, so tests do not depend on run order.
- Use fixtures or factories for repeatable records, and unique values where fields must be unique.
- Keep real personal data out of test environments. Synthetic data avoids compliance problems.
Running tests in CI
Tests only protect you if they run automatically. Wire them into CI/CD so that every pull request runs the fast tests and a merge runs the full set.
- 01Pull requestfunctional and contract
- 02Mergeintegration, fresh environment
- 03Scheduleload and deeper security, before releases
Fail the build on a failing test and publish the report. Keep the pipeline fast, because a slow suite gets skipped.
What to automate first
If you have no automated API tests today, work in this order:
- The critical path: sign-in, the core create-and-read flows, and anything that touches money or personal data.
- A smoke test that hits every endpoint once and checks it responds, so deployments fail loudly.
- Every bug you fix. A test that reproduces the bug is the cheapest regression testing there is.
- Contract checks for any API consumed by another team or a mobile app.
- Load and security tests for the endpoints with the most traffic or the most sensitive data.
A small set of tests on the right endpoints beats hundreds of shallow ones. Before calling an endpoint covered, check:
- The happy path returns the right status and body
- Invalid and missing input return clear errors
- A missing token returns 401 and a token without permission returns 403
- Test data is created and cleaned up by the test itself
- The test runs in the pipeline, not only on a laptop
How this looks at Techdome
We build Sparrow, an open-source, local-first API testing, mocking and monitoring suite, so the topics in this article are ones we work on directly. Sparrow is built with Rust, TypeScript and SQLite, and it is listed on the Microsoft Azure Marketplace. It reached #4 Product of the Day on Product Hunt in two separate launches.
Our software testing and QA work follows the order above. For a distributed-systems engagement with a global technology services corporation, the results included 100% integration tests (A Global Technology Services & Software Corporation).
Takeaways
- Test the API directly: it is faster, steadier and closer to the business rules than UI tests.
- Cover five types over time: functional, contract, integration, load and security.
- Mock at system edges and use real components inside, and manage test data so runs are independent.
- Run fast tests on every pull request and slower ones on merge or on a schedule.
- Start with the critical path, a smoke test and a regression test for every fixed bug.
Have a project like this? Talk to our engineers.


