← All Articles Β· Β· 12 min read

API Testing in 2026: From cURL to Automated Test Suites

Complete guide to API testing: starting with cURL basics, moving to Postman/Insomnia, then automated test suites with JavaScript and Python. Includes real API examples.

apitestingcurlhttppostmanautomation

API Testing in 2026: From cURL to Automated Test Suites

Why cURL is Still the Best Starting Point

Before GUI tools, start with cURL. It forces you to understand what’s actually happening under the hood.

# GET request
curl https://api.example.com/users

# GET with headers
curl -H "Authorization: Bearer $TOKEN" \
     -H "Accept: application/json" \
     https://api.example.com/users/123

# POST with JSON body
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice", "email": "alice@example.com"}'

# PUT
curl -X PUT https://api.example.com/users/123 \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice Updated"}'

# DELETE
curl -X DELETE https://api.example.com/users/123

# Save response to file
curl -s https://api.example.com/users > users.json

Real API Testing Workflow

# 1. Login and extract token
TOKEN=$(curl -s -X POST https://api.example.com/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","password":"secret"}' \
  | jq -r '.token')

# 2. Use token to get protected resource
curl -H "Authorization: Bearer $TOKEN" \
     https://api.example.com/protected

From cURL to JavaScript Tests

// test/api.test.js
import { test, expect } from '@playwright/test';

test('GET /users returns 200 and array', async ({ request }) => {
  const response = await request.get('https://jsonplaceholder.typicode.com/users');
  expect(response.status()).toBe(200);
  const users = await response.json();
  expect(Array.isArray(users)).toBe(true);
  expect(users.length).toBeGreaterThan(0);
});

test('POST /users creates new user', async ({ request }) => {
  const newUser = { name: 'Alice', email: 'alice@example.com' };
  const response = await request.post('https://jsonplaceholder.typicode.com/users', {
    data: newUser,
    headers: { 'Content-Type': 'application/json' }
  });
  expect(response.status()).toBe(201);
  const created = await response.json();
  expect(created.name).toBe('Alice');
  expect(created.id).toBeDefined();
});

Python with requests

import requests

BASE = "https://jsonplaceholder.typicode.com"

def test_get_users():
    r = requests.get(f"{BASE}/users")
    assert r.status_code == 200
    assert isinstance(r.json(), list)

def test_create_user():
    payload = {"name": "Alice", "email": "alice@example.com"}
    r = requests.post(f"{BASE}/users", json=payload)
    assert r.status_code == 201
    data = r.json()
    assert data["name"] == "Alice"
    assert "id" in data

HTTP Status Codes You Must Know

CodeMeaningWhen
200OKSuccessful GET, PUT
201CreatedSuccessful POST
204No ContentSuccessful DELETE
400Bad RequestInvalid JSON, missing fields
401UnauthorizedMissing or invalid token
403ForbiddenValid token, no permission
404Not FoundResource doesn’t exist
429Too Many RequestsRate limit hit
500Server ErrorAPI bug

Always Test These Edge Cases

  1. Empty body on POST β†’ 400
  2. Invalid JSON β†’ 400
  3. Missing required fields β†’ 400
  4. Wrong content-type β†’ 400 or 415
  5. Expired token β†’ 401
  6. Valid token, wrong permissions β†’ 403
  7. Concurrent requests β†’ race condition check

Free Newsletter

Level Up Your Dev Workflow

Get new tools, guides, and productivity tips delivered to your inbox.

Plus: grab the free Developer Productivity Checklist when you subscribe.

Found this guide useful? Check out our free developer tools.