Testing APIs
Your API is a contract between front-end and back-end. Bugs in the API affect every consumer. Testing APIs thoroughly catches regressions before they reach production and waste your users' time.
Manual Testing with Postman
Postman is the standard tool for API testing. Send requests, inspect responses, set headers, manage environments. It's intuitive and powerful.
Create collections of requests (get user, create post, etc.). Organize into folders. Run requests individually or in sequence. Check responses match expectations. This is valuable for development and quick verification.
Automated API Tests
Manual testing doesn't scale. Write automated tests. Make HTTP requests, inspect responses, assert on data. Run tests in CI/CD on every commit. Catch regressions before they reach production.
Jest, Mocha, pytest, and others support API testing. A test might be: POST /api/users, assert 201 response, assert user object has expected fields.
Test Pyramid for APIs
Unit tests: test functions in isolation. Given input, expect output. Fast, numerous. Database is mocked.
Integration tests: test the full stack. API endpoint, database, maybe external services. Slower but closer to reality.
End-to-end tests: test complete flows. User signs up, creates post, likes a comment. The whole application. Slowest but most comprehensive.
The pyramid: many unit tests, fewer integration tests, few end-to-end tests. This provides fast feedback (unit tests) with broader coverage.
What to Test in APIs
Happy path: normal operation. POST /api/users with valid data succeeds. GET /api/users returns users. DELETE /api/users/1 removes the user.
Error cases: invalid input (POST /api/users with no email fails), not found (GET /api/users/999 returns 404), authentication (GET /api/protected without token returns 401).
Authorization: users can access their own data but not others'. Admin endpoints require admin role.
Edge cases: empty arrays, null values, maximum length strings, special characters in inputs.
Contract Testing
Contract tests verify that the API matches what consumers expect. Pact is the main tool. Consumers specify the requests they make and responses they expect. Providers verify they satisfy the contracts.
Contract testing is valuable in microservices. Service A depends on Service B's API. Contract tests ensure they stay in sync without running the full integration.
Mocking External Dependencies
Tests shouldn't call real external services. A test calling Stripe is slow and has side effects (real charges). Mock external services using nock (JavaScript) or responses (Python).
Define mock responses. When your code calls the external service, the mock intercepts and returns the expected response. Tests run fast and have no side effects.
Test Databases
Integration tests need a database. Options: an in-memory database for speed (SQLite in memory), a separate test database, Docker containers.
Isolation is critical. Tests shouldn't affect each other. Run each test in a transaction, roll back after. This ensures clean state.
Running Tests in CI
CI (Continuous Integration) runs tests on every commit. A pull request includes tests. CI runs them. If tests fail, the PR can't be merged. This catches regressions immediately.
In GitHub Actions, GitLab CI, or Jenkins, set up jobs that run: npm test or pytest. Fail the build if tests fail.
Smoke Testing in Staging
Before production, deploy to staging and run automated smoke tests. Basic health checks: API responds, database connection works, critical endpoints function.
Smoke tests catch deployment issues before they hit production. A missing environment variable, a misconfigured dependency—smoke tests catch these.
API Monitoring in Production
Monitor production API health. Response times, error rates, latency. Alert when metrics exceed thresholds.
Services like Datadog, New Relic, or open-source solutions like Prometheus track this. Use them to understand production behavior and catch issues early.
| Type | Speed | Coverage | Setup Effort | Best For |
|---|---|---|---|---|
| Unit tests | Very fast | Narrow, implementation level | Low | Function correctness |
| Integration tests | Moderate | Broader, with real database | Moderate | API contracts |
| End-to-end tests | Slow | Comprehensive, full flow | High | User workflows |
| Contract tests | Fast | API compatibility | Moderate | Microservices |
| Smoke tests | Very fast | Basic health | Low | Post-deployment |