Complete Reference · Beginner to Expert

API Testing
Quick Reference

Everything you need to understand, test, and master APIs — from HTTP basics to advanced automation scripts.

REST Postman Python Requests Security Testing REST Assured Automation
01

What is an API?

The foundation — understanding what you're actually testing

API Definition

Application Programming Interface — a contract between two software systems defining how they communicate. An API exposes specific endpoints that accept requests and return responses without exposing internal implementation details.

Why Test APIs?

APIs are the backbone of modern apps. A broken API breaks everything built on top of it. API testing catches issues early, validates business logic, and ensures reliability before the UI is even built. Faster to test, cheaper to fix.

API Types You'll Encounter

TypeDescriptionCommon Use
RESTUses HTTP methods, stateless, JSON responsesWeb/mobile apps — most common
SOAPXML-based, strict contract via WSDLBanking, legacy enterprise systems
GraphQLQuery language — ask for exactly what you needFlexible frontends (GitHub, Shopify)
gRPCGoogle's binary protocol, very fastMicroservices, internal services
WebSocketPersistent two-way connectionReal-time chat, live dashboards
💡
Beginner TipThink of an API like a restaurant menu. You (the client) place an order (request). The kitchen (server) prepares it and sends back your food (response). You never see the kitchen internals.
02

HTTP Fundamentals

The protocol that powers every REST API request

Anatomy of an HTTP Request

HTTP Request Structure
POST /api/users HTTP/1.1
Host:          api.example.com
Content-Type:  application/json
Authorization: Bearer eyJhbGci...
Accept:        application/json

// Request Body (payload)
{
  "name": "Alice",
  "email": "alice@example.com"
}

Anatomy of an HTTP Response

HTTP Response Structure
HTTP/1.1 201 Created
Content-Type:  application/json
X-Request-Id:  abc-123

// Response Body
{
  "id": 42,
  "name": "Alice",
  "email": "alice@example.com",
  "createdAt": "2026-05-22T10:00:00Z"
}

URL Structure

https://api.site.com/v1/users?role=admin&page=2


Scheme → https
Host → api.site.com
Path → /v1/users
Query → role=admin&page=2

Path Parameters

Embedded in the URL path, identify a specific resource.


GET /users/42

Here 42 is the path param (user ID).

Query Parameters

After ?, used for filtering, sorting, pagination.


GET /users?role=admin&sort=asc&limit=20

03

HTTP Methods (Verbs)

CRUD operations mapped to HTTP — know these cold

MethodCRUDDescriptionHas Body?Idempotent?
GETReadRetrieve a resource. Never modify data.NoYes
POSTCreateCreate a new resource. Body contains data.YesNo
PUTUpdate (full)Replace entire resource. Send all fields.YesYes
PATCHUpdate (partial)Update specific fields only.YesSometimes
DELETEDeleteRemove a resource by ID.RarelyYes
HEADReadLike GET but returns headers only, no body.NoYes
OPTIONSMetaReturns allowed methods for a URL. Used in CORS.NoYes
📌
Idempotent means calling the same request multiple times produces the same result. GET, PUT, DELETE are idempotent. POST is NOT — calling POST twice creates two resources.
04

HTTP Status Codes

The server's answer to your request — memorise these

2xx — Success

200OK — standard success for GET/PUT
201Created — resource created (POST)
202Accepted — async operation queued
204No Content — success, no body (DELETE)

3xx — Redirection

301Moved Permanently — update your bookmarks
302Found — temporary redirect
304Not Modified — use cached version

4xx — Client Errors

400Bad Request — malformed body/params
401Unauthorized — not authenticated
403Forbidden — authenticated but no permission
404Not Found — resource doesn't exist
405Method Not Allowed — wrong HTTP verb
409Conflict — duplicate resource
422Unprocessable Entity — validation failed
429Too Many Requests — rate limited

5xx — Server Errors

500Internal Server Error — generic crash
501Not Implemented — feature not built
502Bad Gateway — proxy got bad response
503Service Unavailable — down/overloaded
504Gateway Timeout — upstream timed out
⚠️
401 vs 403 — 401 means "I don't know who you are, please log in." 403 means "I know who you are, but you're not allowed here." This distinction matters for security testing.
05

HTTP Headers

Metadata attached to requests and responses

Common Request Headers

Request Headers
Content-Type:    application/json
Accept:          application/json
Authorization:   Bearer <token>
X-API-Key:       abc123
Accept-Language: en-US
Cache-Control:   no-cache
User-Agent:      PostmanRuntime/7.32

Common Response Headers

Response Headers
Content-Type:      application/json
Content-Length:    248
X-Request-Id:      a7b2c3d4
X-Rate-Limit:      100
X-Rate-Remaining:  87
Set-Cookie:        session=xyz; HttpOnly
ETag:              "abc123"
💡
Always test headers! Missing Content-Type: application/json is one of the most common causes of 400 errors. Always verify both request and response headers in your test assertions.
06

Authentication & Authorization

Proving identity and controlling access — critical for secure API testing

API Key

Simplest form. A static key passed in a header or query param. No expiration unless rotated manually.

// In Header
X-API-Key: sk_live_abc123xyz

// In Query Param
GET /data?api_key=sk_live_abc123xyz

Basic Auth

Username and password encoded in Base64. Insecure over HTTP — always use HTTPS.

// Format: Base64(username:password)
Authorization: Basic dXNlcjpwYXNz

// In curl
curl -u username:password https://api.example.com

Bearer Token / JWT

Most common for modern REST APIs. Login once to get a token, use it in subsequent requests. Tokens expire.

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

// JWT has 3 parts: Header.Payload.Signature
// Decode at jwt.io -- NEVER expose the secret key

OAuth 2.0

Industry standard for delegated access. User authorises an app to act on their behalf.

// Step 1: Get Authorization Code
GET /oauth/authorize?client_id=abc&response_type=code

// Step 2: Exchange for Access Token
POST /oauth/token
{ "code": "xyz", "grant_type": "authorization_code" }

// Step 3: Use the Token
Authorization: Bearer <access_token>
⚠️
Auth Testing Tip — Always test: (1) missing token → 401, (2) expired token → 401, (3) wrong role token → 403, (4) tampered token → 401/403. These are the most common security gaps.
07

API Testing Tools

Pick the right tool for the right job

Postman

The most popular GUI tool. Supports collections, environments, test scripts (JavaScript), mock servers, and CI/CD via Newman. Best for manual + automated testing with team collaboration.

Insomnia

Lightweight alternative to Postman. Great for GraphQL and gRPC. Clean UI, plugin ecosystem. Preferred by developers who want minimal overhead.

cURL

Command-line HTTP client. Available everywhere. Ideal for quick tests, CI pipelines, and scripting. No GUI — pure terminal power.

REST Assured (Java)

Java DSL for REST API testing. Integrates natively with JUnit/TestNG and Maven. Best for Java teams doing automated regression testing.

Python Requests + Pytest

Simple, readable HTTP library for Python. Combine with Pytest for a powerful automation framework. Great for scripting and data-driven tests.

Newman

Postman's CLI runner. Runs Postman collections from the terminal or CI pipelines (Jenkins, GitHub Actions). Export your Postman collection → run in CI.

Swagger / OpenAPI

API documentation standard. The swagger.json / openapi.yaml file defines all endpoints, parameters, and responses. Use it to auto-generate tests.

JMeter

Industry-standard performance and load testing tool. Tests how APIs behave under high traffic — thousands of concurrent users. Essential for performance testing.

08

Types of API Testing

Different dimensions of quality to validate

Test TypeWhat it checksExample
FunctionalAPI does what it's supposed to doPOST /users creates a user with correct fields
ValidationRequest/response schema and data types match specid is always an integer, not a string
AuthenticationEndpoints reject unauthenticated/unauthorised accessMissing token → 401, wrong role → 403
Error HandlingMeaningful errors for bad inputEmpty required field → 400 with clear message
Negative TestingAPI handles invalid/unexpected input gracefullyString instead of integer → 400, not 500
PerformanceResponse time under normal and peak loadGET /products responds under 200ms
Load TestingSystem stability under sustained load1000 concurrent users for 10 minutes
Stress TestingFind the breaking pointRamp up until 503/504 errors appear
SecurityPrevent data leaks, injection, IDOR, etc.User A cannot access User B's data
Contract TestingProvider API matches consumer expectationsPact framework between microservices
RegressionNew changes don't break existing functionalityRun full suite after every deploy
End-to-EndFull user flow through multiple APIsRegister → Login → Buy Product → Get Invoice
09

What to Assert / Verify

A test without assertions is just a request — assert everything that matters

Status Code

Always assert the exact status code. Don't just check "it didn't error" — a 200 when you expected 201 is still a bug.

Response Time

Assert that response time is under your SLA. Common threshold: 200ms for simple reads, 500ms for writes.

Response Body

Check field values, data types, required fields present, no extra sensitive fields leaking in the response.

Response Schema

Validate the structure matches the API contract. Use JSON Schema validation — catch missing/renamed fields automatically.

Headers

Check Content-Type is correct. Check security headers are present like X-Frame-Options and Strict-Transport-Security.

Error Messages

On failure, check error message is informative but doesn't expose internal stack traces or DB query details.

💡
Complete Assertion Checklist — For every API test: Status code • Response time • Body field values • Field data types • Required fields exist • Sensitive fields NOT exposed • Content-Type header • Pagination metadata if applicable
10

Postman — Complete Guide

From basic requests to automated test suites

Postman Test Scripts (JavaScript)

Tests tab — Postman JavaScript
// 1. Check status code
pm.test("Status is 200", () => {
  pm.response.to.have.status(200);
});

// 2. Check response time
pm.test("Responds within 500ms", () => {
  pm.expect(pm.response.responseTime).to.be.below(500);
});

// 3. Parse and check JSON body
const json = pm.response.json();
pm.test("User name is Alice", () => {
  pm.expect(json.name).to.eql("Alice");
});

// 4. Check field exists and type
pm.test("ID is a number", () => {
  pm.expect(json.id).to.be.a("number");
});

// 5. Check header
pm.test("Content-Type is JSON", () => {
  pm.expect(pm.response.headers.get("Content-Type"))
    .to.include("application/json");
});

// 6. Store value in environment variable
pm.environment.set("userId", json.id);

Pre-request Scripts

Pre-request Script — runs BEFORE the request
// Generate dynamic timestamp
pm.environment.set("timestamp", new Date().toISOString());

// Generate random email for test data
const rand = Math.random().toString(36).substring(7);
pm.environment.set("testEmail", `test_${rand}@example.com`);

// Read environment variable
const token = pm.environment.get("authToken");

Environments & Variables

Variables in request URL / body
// Use double curly braces in URL
GET {{baseUrl}}/users/{{userId}}

// In request body
{
  "email": "{{testEmail}}",
  "token": "{{authToken}}"
}

// Scope priority: local > data > environment > collection > global

Running with Newman (CLI)

Terminal / CI Pipeline
# Install Newman
npm install -g newman

# Run a collection with environment
newman run collection.json -e environment.json

# Run with HTML report
newman run collection.json -e env.json \
  --reporters html \
  --reporter-html-export report.html

# Run with data file (data-driven testing)
newman run collection.json -d testdata.csv
11

REST Assured (Java)

Fluent Java DSL for elegant API test automation

Basic GET Request

Java — REST Assured
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;

// Simple GET test with assertions
given()
  .baseUri("https://api.example.com")
  .header("Authorization", "Bearer " + token)
.when()
  .get("/users/1")
.then()
  .statusCode(200)
  .body("name", equalTo("Alice"))
  .body("id", equalTo(1))
  .time(lessThan(500L));

POST with Body

Java — POST Request
String requestBody = """
  {
    "name": "Bob",
    "email": "bob@example.com"
  }
  """;

Response response =
given()
  .contentType("application/json")
  .body(requestBody)
.when()
  .post("/users")
.then()
  .statusCode(201)
  .body("name", equalTo("Bob"))
  .extract().response();

int newId = response.path("id"); // extract for chaining

JSON Schema Validation

Java — Schema Validation
import static io.restassured.module.jsv.JsonSchemaValidator.*;

given()
  .get("/users/1")
.then()
  .statusCode(200)
  .body(matchesJsonSchemaInClasspath("user-schema.json"));

// user-schema.json in src/test/resources/
// Validates field types, required fields, formats automatically
12

Python API Testing

requests + pytest = powerful, readable automation

requests Library — All Methods

Python — requests
import requests

BASE_URL = "https://api.example.com"
TOKEN = "your_bearer_token"
HEADERS = {
    "Authorization": f"Bearer {TOKEN}",
    "Content-Type": "application/json"
}

# GET
response = requests.get(f"{BASE_URL}/users/1", headers=HEADERS)
print(response.status_code)              # 200
print(response.json())                    # parsed dict
print(response.elapsed.total_seconds())   # response time
print(response.headers["Content-Type"])  # response header

# POST
payload = {"name": "Bob", "email": "bob@example.com"}
r = requests.post(f"{BASE_URL}/users", json=payload, headers=HEADERS)
print(r.status_code)  # 201

# PUT (full update)
r = requests.put(f"{BASE_URL}/users/1", json=payload, headers=HEADERS)

# PATCH (partial update)
r = requests.patch(f"{BASE_URL}/users/1", json={"name": "Alice"}, headers=HEADERS)

# DELETE
r = requests.delete(f"{BASE_URL}/users/1", headers=HEADERS)
print(r.status_code)  # 204

Pytest Test Suite

Python — test_users.py
import pytest
import requests

BASE = "https://api.example.com"

@pytest.fixture(scope="module")
def auth_token():
    r = requests.post(f"{BASE}/auth/login", json={
        "username": "testuser",
        "password": "pass123"
    })
    return r.json()["token"]

def test_get_user(auth_token):
    r = requests.get(f"{BASE}/users/1",
                     headers={"Authorization": f"Bearer {auth_token}"})
    assert r.status_code == 200
    assert r.json()["id"] == 1
    assert isinstance(r.json()["name"], str)
    assert r.elapsed.total_seconds() < 0.5

def test_create_user(auth_token):
    payload = {"name": "Test User", "email": "test@example.com"}
    r = requests.post(f"{BASE}/users", json=payload,
                      headers={"Authorization": f"Bearer {auth_token}"})
    assert r.status_code == 201
    assert "id" in r.json()

def test_unauthorized_access():
    r = requests.get(f"{BASE}/users/1")  # no token
    assert r.status_code == 401

@pytest.mark.parametrize("user_id", [1, 2, 3])
def test_multiple_users(user_id, auth_token):
    r = requests.get(f"{BASE}/users/{user_id}",
                     headers={"Authorization": f"Bearer {auth_token}"})
    assert r.status_code == 200

Useful CLI Commands

Terminal
# Install libraries
pip install requests pytest pytest-html

# Run all tests
pytest

# Run with verbose output
pytest -v

# Run specific test file
pytest test_users.py

# Run and generate HTML report
pytest --html=report.html --self-contained-html

# Run only tests marked with a tag
pytest -m smoke
13

API Security Testing

OWASP Top 10 for APIs — vulnerabilities you must test for

VulnerabilityWhat it isHow to test
IDORInsecure Direct Object Reference — access others' data by changing an IDAccess /users/2 while logged in as user 1 → should get 403
Broken AuthWeak token validation, no expiry, predictable tokensUse expired/forged JWT; test token rotation
SQL InjectionMalicious SQL in input fields executed by the databaseSend ' OR '1'='1 in query params, check response
XSS via APIScript tags stored via API, executed when renderedPOST a script tag as a name field, verify it's escaped
Mass AssignmentUser sends extra fields (isAdmin: true) that get savedAdd extra fields to POST body, verify they're ignored
Excessive Data ExposureAPI returns sensitive fields not needed by clientCheck if passwords, tokens, PII appear in responses
Rate Limiting MissingNo throttle = brute-force/DoS riskSend 1000 requests rapidly, expect 429 after threshold
Broken Object Level AuthUser can modify/delete resources they don't ownTry DELETE /orders/999 with a different user's token

Quick Security Test Examples

cURL Security Tests
# Test 1: No auth token -- expect 401
curl -X GET https://api.example.com/users/1

# Test 2: IDOR -- access another user's data -- expect 403
curl -H "Authorization: Bearer user1_token" \
     https://api.example.com/users/2

# Test 3: SQL injection in query param
curl "https://api.example.com/search?q=%27%20OR%20%271%27%3D%271"

# Test 4: Mass assignment -- send isAdmin field
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"name":"hacker","isAdmin":true}'
# Verify: isAdmin should be ignored in response
14

Best Practices

Habits that separate good testers from great ones

Test Design

  • Test the happy path AND sad paths (negative tests)
  • Use boundary values: 0, -1, max length, empty string
  • Each test should be independent — no shared state
  • Use descriptive names: should_return_404_when_user_not_found
  • Don't hardcode test data — use variables/fixtures

Data Management

  • Never test against production data
  • Clean up created test data after tests (teardown)
  • Use separate test environments (dev/staging/prod)
  • Store credentials in environment variables, never in code
  • Use data-driven testing for multiple inputs

Automation

  • Integrate tests into CI/CD pipeline
  • Run smoke tests on every deploy
  • Run full regression suite nightly
  • Generate and publish test reports
  • Set response time thresholds — alert on slow APIs

Documentation

  • Always read the API spec/swagger before writing tests
  • Document test coverage — which endpoints are tested
  • Log request/response for failed tests
  • Version your test collections alongside code
  • Share Postman environments with your team via Git
📌
The Testing Pyramid for APIs — Many unit tests → Some integration tests → Few E2E tests. API tests live at the integration level. They're faster and cheaper than UI tests but catch more real integration bugs than unit tests alone.
15

API Test Checklist

Use this for every new API endpoint you test

Functional Checks

  • Happy path returns correct status code
  • Response body has all expected fields
  • Field data types match spec (string, int, bool)
  • Pagination works correctly (page, limit, total)
  • Filtering and sorting parameters work
  • CRUD chain works end-to-end
  • Idempotent methods are actually idempotent

Negative & Edge Cases

  • Non-existent resource → 404
  • Missing required field → 400 with error message
  • Wrong data type → 400 or 422
  • Empty string where not allowed → 400
  • Extremely large payload → handled gracefully
  • Special characters in input → no crash
  • Duplicate create request → 409 Conflict

Auth & Security

  • No token → 401
  • Expired token → 401
  • Valid token, wrong role → 403
  • IDOR: access other user's resources → 403
  • SQL injection in inputs → no DB error
  • Sensitive data not in response (passwords, keys)
  • Rate limit enforced → 429

Performance & Headers

  • Response time under agreed SLA
  • Content-Type: application/json in response
  • No sensitive info in response headers
  • CORS headers correct for cross-origin calls
  • Compression working (gzip) for large responses
  • Load test: acceptable under 100 concurrent users
🚀
Learning Path — (1) Learn HTTP basics & use Postman manually → (2) Write Postman test scripts → (3) Run with Newman in CI → (4) Switch to Python/REST Assured for code-based tests → (5) Add performance and security testing. You're now an API testing expert.