Master API testing from basics to advanced automation with modern tools and frameworks
APIs are like waiters in a restaurant - they take your order (request) and bring back food (response). Testing APIs ensures they deliver the right food every time!
GET - Retrieve data
Like asking "What's on the menu?"
POST - Create new data
Like placing a new order
PUT - Update existing data
Like changing your order
DELETE - Remove data
Like canceling your order
// Success codes
200 OK - Request successful
201 Created - Resource created
204 No Content - Success, no data returned
// Client error codes
400 Bad Request - Invalid data sent
401 Unauthorized - Authentication required
403 Forbidden - No permission
404 Not Found - Resource doesn't exist
// Server error codes
500 Internal Server Error - Server crashed
503 Service Unavailable - Server down
Postman is like a playground for APIs - test requests, save collections, and automate tests visually.
// GET request example
GET https://api.example.com/users
// POST request with body
POST https://api.example.com/users
Headers:
Content-Type: application/json
Body:
{
"name": "Test User",
"email": "test@email.com"
}
// Test status code
pm.test("Status code is 200", function () {
pm.response.to.have.status(200);
});
// Test response time
pm.test("Response time is less than 500ms", function () {
pm.expect(pm.response.responseTime).to.be.below(500);
});
// Test response body
pm.test("User has correct email", function () {
const jsonData = pm.response.json();
pm.expect(jsonData.email).to.eql("test@email.com");
});
// Save data for next request
const userId = pm.response.json().id;
pm.environment.set("userId", userId);
SuperTest lets you write automated API tests in code - perfect for CI/CD pipelines.
// Install SuperTest
npm install --save-dev supertest jest
// tests/api/users.test.js
const request = require('supertest');
const app = require('../../app');
describe('User API', () => {
let userId;
test('GET /api/users - should return all users', async () => {
const response = await request(app)
.get('/api/users')
.expect(200)
.expect('Content-Type', /json/);
expect(response.body).toBeInstanceOf(Array);
expect(response.body.length).toBeGreaterThan(0);
});
test('POST /api/users - should create user', async () => {
const newUser = {
name: 'Test User',
email: 'test@email.com'
};
const response = await request(app)
.post('/api/users')
.send(newUser)
.expect(201);
expect(response.body).toHaveProperty('id');
expect(response.body.name).toBe(newUser.name);
userId = response.body.id;
});
test('PUT /api/users/:id - should update user', async () => {
const updates = { name: 'Updated Name' };
await request(app)
.put(`/api/users/${userId} `)
.send(updates)
.expect(200);
});
test('DELETE /api/users/:id - should delete user', async () => {
await request(app)
.delete(`/api/users/${userId} `)
.expect(204);
});
});
GraphQL is like ordering ร la carte - you specify exactly what data you want.
// GraphQL Query Test
test('should fetch user with specific fields', async () => {
const query = `
query {
user(id: "1") {
id
name
}
}
`;
const response = await request(app)
.post('/graphql')
.send({ query })
.expect(200);
expect(response.body.data.user).toHaveProperty('id');
expect(response.body.data.user).toHaveProperty('name');
});
// GraphQL Mutation Test
test('should create user via mutation', async () => {
const mutation = `
mutation {
createUser(name: "Test", email: "test@email.com") {
id
name
}
}
`;
const response = await request(app)
.post('/graphql')
.send({ query: mutation })
.expect(200);
expect(response.body.data.createUser).toHaveProperty('id');
});
// Test JWT authentication
describe('Authentication', () => {
let authToken;
test('should login and return token', async () => {
const response = await request(app)
.post('/api/auth/login')
.send({
email: 'test@email.com',
password: 'password123'
});
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('token');
authToken = response.body.token;
});
test('should access protected route with token', async () => {
await request(app)
.get('/api/profile')
.set('Authorization', `Bearer ${authToken} `)
.expect(200);
});
test('should reject without token', async () => {
await request(app)
.get('/api/profile')
.expect(401);
});
test('should reject with invalid token', async () => {
await request(app)
.get('/api/profile')
.set('Authorization', 'Bearer invalid-token')
.expect(401);
});
});
Validate API responses match expected structure - like checking if your pizza has all the toppings you ordered.
// Install Joi for validation
npm install joi
// Define schema
const Joi = require('joi');
const userSchema = Joi.object({
id: Joi.number().required(),
name: Joi.string().min(3).required(),
email: Joi.string().email().required(),
age: Joi.number().min(18).optional(),
createdAt: Joi.date().required()
});
// Validate response
test('should match user schema', async () => {
const response = await request(app).get('/api/users/1');
const { error } = userSchema.validate(response.body);
expect(error).toBeUndefined();
});
// Test response time
test('should respond within 500ms', async () => {
const start = Date.now();
await request(app).get('/api/users');
const duration = Date.now() - start;
expect(duration).toBeLessThan(500);
});
// Load testing with k6 (preview)
import http from 'k6/http';
import { check } from 'k6';
export default function() {
const res = http.get('https://api.example.com/users');
check(res, {
'status is 200': (r) => r.status =>= 200,
'response time < 500ms': (r) => r.timings.duration < 500
});
}
Build a complete API testing framework with helpers, fixtures, and organized tests.
// Project Structure
tests/
โโโ api/
โ โโโ users.test.js
โ โโโ products.test.js
โ โโโ orders.test.js
โโโ helpers/
โ โโโ auth.js
โ โโโ testData.js
โโโ fixtures/
โ โโโ users.json
โโโ setup.js
// helpers/auth.js
async function getAuthToken() {
const response = await request(app)
.post('/api/auth/login')
.send({ email: 'test@email.com', password: 'pass' });
return response.body.token;
}
// Run all tests
npm test
You've mastered API testing and automation:
Next: Mobile Testing Automation in Module 5!