█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/Programming Languages/REST APIs/Testing REST APIs
50 minIntermediate

Testing REST APIs

After this lesson, you will be able to: Test REST APIs with Postman collections, automated API tests (Supertest), and load tests (k6).

API tests catch contract drift before it hits clients. Three layers: manual (Postman), automated (Supertest), load (k6). Production teams use all three.

Prerequisites:Rate limiting

Postman collections + Newman

Manual + scriptable test runs.

tsx
// In Postman: build a collection with requests per endpoint.
// Add tests in the Tests tab of each request:
pm.test('Status is 200', () => {
pm.response.to.have.status(200);
});
pm.test('Has expected fields', () => {
const body = pm.response.json();
pm.expect(body).to.have.property('id');
pm.expect(body.email).to.match(/@/);
});
// Export collection + run in CI with Newman:
// npx newman run my-collection.json --env-var TOKEN=$TOKEN

Automated tests with Supertest (Node + Vitest)

Hit your Express app in-process; no HTTP overhead.

python
// npm i -D supertest vitest
import request from 'supertest';
import { describe, it, expect } from 'vitest';
import { app } from '../src/app';
describe('POST /users', () => {
it('creates a user', async () => {
const res = await request(app)
.post('/users')
.send({ email: '[email protected]', name: 'A' })
.expect('Content-Type', /json/)
.expect(201);
expect(res.body.email).toBe('[email protected]');
expect(res.body).toHaveProperty('id');
});
it('returns 422 on invalid email', async () => {
const res = await request(app)
.post('/users')
.send({ email: 'not-an-email', name: 'A' })
.expect(422);
expect(res.body.error).toBe('ValidationError');
});
});

Load testing with k6

JavaScript-scripted load tests.

python
// k6 test script, load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '30s', target: 20 }, // ramp to 20 users
{ duration: '1m', target: 20 }, // hold 20 users
{ duration: '30s', target: 100 }, // spike to 100
{ duration: '30s', target: 0 }, // ramp down
],
thresholds: {
http_req_duration: ['p(95)<300'], // 95% under 300ms
http_req_failed: ['rate<0.01'], // < 1% errors
},
};
export default function () {
const res = http.get('https://api.example.com/users');
check(res, {
'status is 200': (r) => r.status === 200,
'body has data': (r) => r.json('length') > 0,
});
sleep(1);
}
// k6 run load-test.js

💡 Which test layer when

Supertest: in-process tests of your routes. Run on every push. Cover correctness. Postman / Newman: end-to-end against staging/prod. Run on schedule + manually. Cover real-deployment quirks. k6: load + perf. Run before launches, before scale events. Cover capacity. All three together = high confidence.

Contract testing (advanced)

Pact (consumer-driven contracts): client defines what it expects; provider runs those tests against itself. Prevents breaking changes catching either side off-guard. Schemathesis: generates property-based tests from your OpenAPI spec. Catches edge cases you didn't think of. Use these when you have multiple teams sharing an API.

Common mistakes

No tests on error paths (only happy path). Tests that hit the real DB without isolation (flaky). Skipping load testing until prod blows up. Postman collection that lives on one dev's laptop (export + commit to repo).

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←Rate Limiting
Back to REST APIs
GraphQL as Alternative→