⚡ Local SDET practice ground — Selenium · Playwright · Appium · API testingnavtutorial.com ↗
API Testing
All guides ← Hub
REST · mock server included

API testing guide

Run the bundled mock server, then automate it from REST Assured, Playwright, Python or Postman — or explore it live in the playground.

Two ways to practice. (1) The in-browser API Playground lets you fire requests and read JSON responses with zero setup — great for learning and for Playwright UI tests. (2) To hit an endpoint from an external tool (Postman, REST Assured, curl), run the included mock server so you get a real URL.
Hosted on a real domain? If this hub is uploaded to a web host with PHP (e.g. cPanel), the PHP server + the bundled api/.htaccess serve the same routes at https://your-domain/your-folder/api/… — no port, no node. Just swap http://localhost:4000 for that base in the examples below.

1 · Run the mock server

Both versions expose the same endpoints on http://localhost:4000.

cd automation-practice-hub/api
node mock-server.js
# -> Mock API listening on http://localhost:4000
cd automation-practice-hub/api
php -S localhost:4000 mock-server.php
# -> serves the same routes on http://localhost:4000

2 · Endpoint reference

POST/api/login → 200 {token} for Admin/admin123, else 401
GET/api/users?page=1 → paged list
GET/api/users/{id} → 200 user, or 404
POST/api/users → 201 created
PUT/api/users/{id} → 200 updated
DELETE/api/users/{id} → 204
GET/api/products → product list
GET/api/secure → 200 with Authorization: Bearer <token>, else 401
GET/api/status/{code} → echoes that HTTP status

3 · GET a list & assert

import io.restassured.RestAssured;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
import org.testng.annotations.Test;

public class UsersApiTest {
  @Test
  public void listUsers() {
    RestAssured.baseURI = "http://localhost:4000";
    given()
      .queryParam("page", 1)
    .when()
      .get("/api/users")
    .then()
      .statusCode(200)
      .body("page", equalTo(1))
      .body("data.size()", greaterThan(0))
      .body("data[0].id", notNullValue());
  }
}
const { test, expect, request } = require('@playwright/test');

test('list users', async ({ request }) => {
  const res = await request.get('http://localhost:4000/api/users?page=1');
  expect(res.status()).toBe(200);
  const body = await res.json();
  expect(body.page).toBe(1);
  expect(body.data.length).toBeGreaterThan(0);
});
import requests

def test_list_users():
    r = requests.get("http://localhost:4000/api/users", params={"page": 1})
    assert r.status_code == 200
    body = r.json()
    assert body["page"] == 1
    assert len(body["data"]) > 0
curl -s "http://localhost:4000/api/users?page=1" | jq

4 · POST a new user (expect 201)

given()
  .baseUri("http://localhost:4000")
  .contentType("application/json")
  .body("{\"name\":\"Ava\",\"job\":\"SDET\"}")
.when()
  .post("/api/users")
.then()
  .statusCode(201)
  .body("name", equalTo("Ava"))
  .body("id", notNullValue())
  .body("createdAt", notNullValue());
const res = await request.post('http://localhost:4000/api/users', {
  data: { name: 'Ava', job: 'SDET' }
});
expect(res.status()).toBe(201);
const body = await res.json();
expect(body.name).toBe('Ava');
r = requests.post("http://localhost:4000/api/users",
                  json={"name": "Ava", "job": "SDET"})
assert r.status_code == 201
assert r.json()["name"] == "Ava"

5 · Auth flow: login → token → protected route

// 1) login
String token =
  given().contentType("application/json")
         .body("{\"username\":\"Admin\",\"password\":\"admin123\"}")
  .when().post("http://localhost:4000/api/login")
  .then().statusCode(200).extract().path("token");

// 2) call the protected endpoint
given().header("Authorization", "Bearer " + token)
.when().get("http://localhost:4000/api/secure")
.then().statusCode(200).body("message", containsString("granted"));

// 3) negative: no token -> 401
given().when().get("http://localhost:4000/api/secure")
.then().statusCode(401);
login = requests.post("http://localhost:4000/api/login",
        json={"username": "Admin", "password": "admin123"})
token = login.json()["token"]

ok = requests.get("http://localhost:4000/api/secure",
     headers={"Authorization": f"Bearer {token}"})
assert ok.status_code == 200

denied = requests.get("http://localhost:4000/api/secure")
assert denied.status_code == 401

6 · Postman / newman

Import postman_collection.json (included in the api/ folder). Run the whole suite headless from CI with newman:

npm install -g newman
newman run api/postman_collection.json \
  --env-var "baseUrl=http://localhost:4000"
Negative testing. Use /api/status/{code} to force 4xx/5xx responses, and /api/users/9999 to get a real 404 — handy for asserting error bodies and retry logic.