HTTP Headers for API Testing: Content-Type, Accept, Caching and ETag

HTTP Headers for API Testing: Content-Type, Accept, Caching and ETag

Headers are the small key-value lines that travel with every request and response. They decide whether the server reads your body as JSON, who you are, which format comes back, whether a response may be cached, and whether two people editing the same record overwrite each other. Many testers ignore headers and miss whole categories of bugs. In this lesson you will learn the headers that matter for API testing, with real-life examples and live calls.

Quick answerHTTP headers carry metadata about a request or response. Key request headers are Content-Type, Accept, Authorization, If-None-Match and If-Match. Key response headers are Content-Type, Location, Cache-Control, ETag, Allow, Retry-After and WWW-Authenticate. Testers verify that the right headers are sent, the right ones come back, caching behaves correctly (304 Not Modified) and security headers are present.
Advertisement

What Are HTTP Headers? (The Parcel Label Example)

Real-life example: a courier parcel The body is what’s inside the box. The headers are the label on the outside: “Fragile” (how to handle it), “Contents: documents” (Content-Type), “Deliver only to Asha with ID” (Authorization), “Weight 2 kg” (Content-Length), “Return if not delivered by Friday” (expiry). The courier reads the label without opening the box.

Headers are written as Name: value, one per line. Names are case-insensitive: content-type and Content-Type are the same header (Playwright returns all names in lower case).

Request Headers Every Tester Should Know

HeaderExamplePurposeWhat to test
Content-Typeapplication/jsonFormat of the body you sendWrong type → 415
Acceptapplication/xmlFormat you want backUnsupported → 406
AuthorizationBearer eyJhbGci...Who you areMissing/expired/tampered → 401
X-API-Keysqa-key-12345API key auth (custom header)Missing → 401, wrong → 403
If-None-Match"c2aee9e2..."“Send only if changed”Unchanged → 304
If-Match"v3"“Update only if still this version”Stale → 412
User-AgentMyApp/5.2 (Android 15)Identifies the clientVersion-specific behaviour
Accept-Languagehi-INPreferred languageLocalised messages
X-Request-Id7f3c-91aaTrace id for logsEchoed back; appears in logs
Idempotency-Keyord-2026-0001Make POST retries safeSame key → no duplicate
Advertisement

Response Headers Every Tester Should Check

HeaderExampleWhy it matters
Content-Typeapplication/json; charset=UTF-8Client parses the body correctly; wrong type breaks apps
Location.../objects/obj_hoeovqif1vURL of the newly created resource (201)
ETag"v1"Version fingerprint for caching and locking
Cache-Controlno-store, max-age=0Whether and how long to cache
AllowGET, HEADMethods allowed (with 405 and OPTIONS)
Retry-After10When to retry after 429/503
WWW-AuthenticateBasic realm="SQA practice API"Which auth scheme to use (with 401)
Link<...page=2>; rel="next"Pagination navigation
X-Total-Count12Total records for paging UIs
X-RateLimit-Remaining4Calls left in the window

See them live. Press Send and look at link and x-total-count in the output:

GEThttps://sqatools.in/wp-json/sqa-api/v1/users?per_page=2
curl -i \
  "https://sqatools.in/wp-json/sqa-api/v1/users?per_page=2"

Content Negotiation: Content-Type vs Accept

These two are confused all the time:

  • Content-Type describes the body being sent (in a request: what you send; in a response: what the server sends).
  • Accept is a request header saying what format you would like back.
Restaurant analogy Content-Type is the language your order slip is written in. Accept is “please reply in English”. If the kitchen only understands Hindi slips, an English slip gets 415; if the waiter can’t reply in French, you get 406.
GEThttps://sqatools.in/wp-json/sqa-api/v1/users/1
curl -i \
  -H "Accept: text/csv" \
  "https://sqatools.in/wp-json/sqa-api/v1/users/1"

The practice API answers 406 because it can return only JSON or XML. Change Accept to application/xml and you get XML.

Advertisement

Caching Headers: Cache-Control, ETag and 304

Caching saves bandwidth and makes apps fast. A product image or a catalogue page that hasn’t changed doesn’t need to be downloaded again.

Cache-Control

  • max-age=3600: the response can be reused for 1 hour.
  • no-cache: may be stored, but must be revalidated with the server before use.
  • no-store: never store it. Required for sensitive data such as bank balances, OTPs and personal details.
  • private vs public: whether shared caches (CDN, proxies) may store it.
Real bug: cached account page A banking API returned account details with Cache-Control: public, max-age=600. A shared corporate proxy cached it, and the next employee saw a colleague’s balance. Testers should verify that every personal-data response has no-store or private.

ETag and conditional requests

An ETag is a fingerprint of the current version of a resource. The client stores it and next time asks: “send it only if it changed” using If-None-Match.

  1. GET /products/101 → 200, ETag: "c2aee9e25c4daa9445361e1bb4a749f7".
  2. GET /products/101 with If-None-Match: "c2aee9e25c4daa9445361e1bb4a749f7" → 304 Not Modified, empty body.
GEThttps://sqatools.in/wp-json/sqa-api/v1/products/101
curl -i \
  -H "If-None-Match: \"c2aee9e25c4daa9445361e1bb4a749f7\"" \
  "https://sqatools.in/wp-json/sqa-api/v1/products/101"

If the browser shows 200 instead of 304 here, the product data has changed since this lesson was written; copy the new ETag from a normal GET and try again.

Advertisement

Optimistic Locking with If-Match (Prevent Lost Updates)

Real-life example: two support agents, one ticket Agent A and Agent B both open ticket #500 (version v3). A changes the priority and saves (now v4). B, still looking at the old screen, changes the status and saves. Without protection, B’s save overwrites A’s priority change: a lost update. With If-Match: "v3", B’s save is rejected with 412 Precondition Failed and B is told to reload.
# 1. Create an object, note ETag "v1"
curl -i -X PUT "https://sqatools.in/wp-json/sqa-api/v1/objects/ticket-500" \
  -H "Content-Type: application/json" -d '{"name":"Ticket 500","data":{"priority":"low"}}'

# 2. Update with the current version: 200, ETag becomes "v2"
curl -i -X PATCH ".../objects/ticket-500" -H "If-Match: \"v1\"" \
  -H "Content-Type: application/json" -d '{"data":{"priority":"high"}}'

# 3. Update again with the OLD version: 412 Precondition Failed
curl -i -X PATCH ".../objects/ticket-500" -H "If-Match: \"v1\"" \
  -H "Content-Type: application/json" -d '{"data":{"status":"closed"}}'

The practice API’s 412 message: If-Match “v1” does not match the current version “v2”. Someone changed the object; GET it again.

Security Headers to Verify

HeaderExpected valueProtects against
Strict-Transport-Securitymax-age=31536000; includeSubDomainsHTTPS downgrade attacks
X-Content-Type-OptionsnosniffBrowsers guessing the wrong content type
Cache-Controlno-store for personal dataData left in caches
Access-Control-Allow-OriginSpecific trusted origins, not * with credentialsCross-site data theft (CORS)
No Server / X-Powered-By versionsRemoved or genericAttackers targeting known versions

CORS is covered in detail in HTTPS, Cookies and CORS.

Advertisement

Testing Headers with Playwright

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

const BASE = 'https://sqatools.in/wp-json/sqa-api/v1';

test('JSON content type and no caching of user data', async ({ request }) => {
  const res = await request.get(`${BASE}/users/1`);
  const h = res.headers();                       // all names are lower case
  expect(h['content-type']).toContain('application/json');
  expect(h['cache-control']).toContain('no-store');
  expect(h['x-content-type-options']).toBe('nosniff');
});

test('ETag + If-None-Match gives 304', async ({ request }) => {
  const first = await request.get(`${BASE}/products/101`);
  const etag = first.headers()['etag'];
  expect(etag).toBeTruthy();

  const second = await request.get(`${BASE}/products/101`, {
    headers: { 'If-None-Match': etag },
  });
  expect(second.status()).toBe(304);
  expect((await second.body()).length).toBe(0);
});

test('stale If-Match is rejected with 412', async ({ request }) => {
  const url = `${BASE}/objects/lock-${Date.now()}`;
  await request.put(url, { data: { name: 'Ticket', data: { priority: 'low' }, ttl: 60 } });  // v1
  await request.patch(url, { data: { data: { priority: 'high' } }, headers: { 'If-Match': '"v1"' } }); // v2
  const stale = await request.patch(url, { data: { data: { status: 'closed' } }, headers: { 'If-Match': '"v1"' } });
  expect(stale.status()).toBe(412);
});

test('pagination headers', async ({ request }) => {
  const res = await request.get(`${BASE}/users?per_page=5`);
  expect(res.headers()['x-total-count']).toBe('12');
  expect(res.headers()['link']).toContain('rel="next"');
});
Advertisement

Header Testing Checklist

  • Correct Content-Type on every response, including errors.
  • Missing/wrong Content-Type on requests gives 415, not 500.
  • Unsupported Accept gives 406.
  • Location on 201; Allow on 405; WWW-Authenticate on 401; Retry-After on 429/503.
  • Personal data is never publicly cacheable.
  • ETag changes when the resource changes; 304 when it doesn’t; 412 on stale If-Match.
  • No version-revealing headers; security headers present.
  • Header names treated case-insensitively.
Advertisement

Interview Questions: HTTP Headers

What is the difference between Content-Type and Accept headers?

Content-Type describes the format of the body being sent (by the client in a request or by the server in a response). Accept is sent by the client to say which response formats it can handle. A wrong Content-Type leads to 415; an Accept the server can’t satisfy leads to 406.

What is an ETag?

An ETag is an identifier for a specific version of a resource returned in a response header. Clients send it back with If-None-Match to get 304 Not Modified when nothing changed, or with If-Match to update only if the resource is still at that version.

What is optimistic locking in APIs?

A concurrency control technique where updates include the expected version (If-Match with the ETag). If someone else changed the resource first, the server returns 412 Precondition Failed instead of silently overwriting their change.

What is the difference between no-cache and no-store?

no-cache allows storing the response but requires revalidation with the server before each reuse. no-store forbids storing it anywhere and is required for sensitive data.

Which headers do you check in API testing?

Content-Type, Cache-Control, Location for creates, ETag, Allow for 405, WWW-Authenticate for 401, Retry-After for 429 and 503, pagination headers, rate limit headers, CORS headers and security headers such as Strict-Transport-Security and X-Content-Type-Options.

Are HTTP header names case-sensitive?

No. Header names are case-insensitive, so tests should not depend on case. Header values may be case-sensitive depending on the header.

Where do you send an authentication token?

Usually in the Authorization header, for example Authorization: Bearer token. Some APIs use custom headers like X-API-Key. Tokens should not be sent in query strings because URLs are logged.

How does a client know how long to wait after 429 or 503?

From the Retry-After header, which contains seconds or a date. Rate limit headers such as X-RateLimit-Reset may also be provided.

What is the purpose of a request id header?

A request or correlation id (for example X-Request-Id) uniquely identifies a call across all services and logs. Including it in bug reports lets developers find the exact failing request.

How do you test that a response was cached correctly?

Check Cache-Control and ETag on the first response, send a conditional request with If-None-Match and expect 304, change the resource and expect 200 with a new ETag, and confirm that personal data responses are not cacheable.

Advertisement
View the full API testing syllabus

HTTP Status Codes: Complete List with API Testing Examples

HTTP Status Codes: Complete List with API Testing Examples

The status code is the first thing every client reads in an API response, and the first thing a tester should assert. A login API that answers 200 OK with “invalid password” in the body, or a typo in a search that crashes with 500, are real bugs that ship to production every day. This lesson is your complete HTTP status codes reference for API testing: every code you will meet, what it means in real life, and how to test it on live endpoints.

Quick answerHTTP status codes are 3-digit numbers grouped into five classes: 1xx informational, 2xx success (200 OK, 201 Created, 204 No Content), 3xx redirection (301, 302, 304), 4xx client errors (400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 422 Unprocessable Content, 429 Too Many Requests) and 5xx server errors (500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout). In API testing you verify that every scenario returns the correct, most specific code.
Advertisement

The 5 Classes of HTTP Status Codes

ClassMeaningReal-life analogy (courier delivery)Who should act
1xx InformationalRequest received, continue“Parcel picked up, in process”Nobody, usually invisible
2xx SuccessIt worked“Delivered”Client uses the result
3xx RedirectionLook somewhere else“Customer moved, forwarded to new address”Client follows the new location
4xx Client errorYour request is wrong“Incomplete address” or “no one authorised to receive”Client must fix the request
5xx Server errorServer failed“Our van broke down”Server team must fix; client may retry
The golden rule for testers A 4xx means “the client did something wrong”, a 5xx means “the server is broken”. So any 5xx caused by user input is a bug. Invalid input must produce a 4xx with a helpful message.

Try Any Status Code Live

The practice API has a helper endpoint that returns whatever status you ask for: GET /status/{code}. Use it to check how your client, Postman tests or Playwright framework handle each code. Here is a 503 with a Retry-After header:

GEThttps://sqatools.in/wp-json/sqa-api/v1/status/503
curl -i \
  "https://sqatools.in/wp-json/sqa-api/v1/status/503"

Edit the URL to /status/201, /status/204, /status/409 and more. An invalid code such as /status/700 returns 400.

Advertisement

2xx Success Codes

CodeNameWhen to expect itWhat to assert
200OKSuccessful GET, PUT, PATCH; POST actions that don’t create (e.g. login, search)Body contains the expected data
201CreatedPOST (or PUT) created a new resourceLocation header + new id in the body
202AcceptedAsync work queued (report export, bulk upload)Job id; poll until done
204No ContentDELETE, or update with nothing to returnBody is truly empty
206Partial ContentRange requests (video streaming, resumable downloads)Content-Range header

200 vs 201 vs 204

  • Create an order → 201 Created (not 200). The practice API’s POST /objects follows this rule.
  • Fetch an order → 200 OK.
  • Delete an order → 204 No Content.
Classic bug: “200 with an error inside” HTTP 200 with body {"success": false, "message": "Invalid OTP"}. Monitoring sees no errors, caches may store the failure, and clients that only check status think it worked. Report it: the status should be a 4xx.

3xx Redirection Codes

CodeNameReal exampleKeeps method and body?
301Moved PermanentlyOld API v1 URL permanently moved; SEO-safe redirectNot guaranteed (clients may switch POST to GET)
302Found (temporary)Login redirect to SSO pageNot guaranteed
303See OtherAfter POST payment, redirect to the receipt pageNo, always becomes GET
304Not ModifiedCached product data still valid (ETag matched)No body sent
307Temporary RedirectRequest moved to another server during maintenanceYes
308Permanent RedirectPermanent move that must keep POST as POSTYes

Practice: GET /redirect returns 302; POST /redirect?status=307 keeps the POST; POST /redirect?status=303 switches to GET. Conditional GET: request /products/101 with If-None-Match set to its ETag and you get 304. Details in HTTP headers and caching.

Advertisement

4xx Client Error Codes

CodeNameMeaningReal-life example
400Bad RequestMalformed request: bad JSON, invalid parameter format/users/abc when id must be a number
401UnauthorizedNot authenticated: missing, invalid or expired credentialsSession expired in the banking app
403ForbiddenAuthenticated, but not allowedViewer tries to delete a record
404Not FoundResource doesn’t exist (or is hidden from you)Order id 999 doesn’t exist
405Method Not AllowedMethod not supported on this URLDELETE /products/101
406Not AcceptableServer can’t produce the format in AcceptAsking for CSV from a JSON-only API
408Request TimeoutClient took too long to send the requestVery slow upload
409ConflictConflicts with current stateUsername already taken; seat already booked
410GonePermanently removedRetired API version
412Precondition FailedIf-Match version is staleTwo agents editing the same ticket
413Content Too LargeBody over the limitUploading a 50 MB profile photo
415Unsupported Media TypeWrong Content-TypeSending text/plain to a JSON API
422Unprocessable ContentWell-formed but fails validation rulesAge 17 when minimum is 18
429Too Many RequestsRate limit exceededOTP requested 6 times in a minute
Advertisement

The Confusing Pairs (Interview Favourites)

401 Unauthorized vs 403 Forbidden

Office building analogy No ID card at the gate → the guard stops you: 401 (“who are you?”). Valid ID card, but you try to enter the server room you have no access to → 403 (“I know who you are, but you are not allowed”).

A 401 should include a WWW-Authenticate header. Try it on the Basic auth endpoint with no credentials:

GEThttps://sqatools.in/wp-json/sqa-api/v1/basic/profile
curl -i \
  "https://sqatools.in/wp-json/sqa-api/v1/basic/profile"

On the practice API, a missing API key gives 401, a wrong API key gives 403, and a viewer token trying to create gives 403.

400 Bad Request vs 422 Unprocessable Content

  • 400: the server can’t even read it. Broken JSON, empty body, a JSON array instead of an object, text where a number is required in the URL.
  • 422: the JSON is valid, but the values break business rules: invalid email, age out of range, unknown enum value.
POSThttps://sqatools.in/wp-json/sqa-api/v1/validate/user
curl -i \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"name":"A","email":"not-an-email","age":17}' \
  "https://sqatools.in/wp-json/sqa-api/v1/validate/user"

The response lists every failing field at once, which is the behaviour you want from a well-designed API.

404 Not Found vs 403 for Hidden Resources

For security, many APIs return 404 instead of 403 when you request another user’s private resource, so attackers can’t even learn that it exists. Both are acceptable; returning the data is not.

409 Conflict vs 412 Precondition Failed

409 is a business conflict (duplicate email). 412 is a technical version conflict when you send If-Match with an old ETag (optimistic locking). The practice API’s /objects supports both scenarios.

Advertisement

5xx Server Error Codes

CodeNameTypical causeWhat testers do
500Internal Server ErrorUnhandled exception, null pointer, bad queryAlways a bug; attach request + trace id
501Not ImplementedFeature/method not built yetCheck against requirements
502Bad GatewayGateway got an invalid reply from the service behind itCheck service health and logs
503Service UnavailableMaintenance or overload; should send Retry-AfterVerify clients back off and retry
504Gateway TimeoutService behind the gateway too slowPerformance investigation
Security check on 5xx Error responses must never contain stack traces, SQL queries, file paths or framework versions. Attackers use these details. Always read the body of a 500 during testing.

Status Codes for Each HTTP Method

MethodSuccessCommon errors to test
GET200 (304 if cached)400, 401, 403, 404
POST201 (200 for actions, 202 async)400, 401, 403, 409, 413, 415, 422, 429
PUT200 / 201 (upsert) / 204400, 404, 409, 412, 422
PATCH200 / 204400, 404, 412, 422
DELETE204 / 200401, 403, 404, 409
Advertisement

Automating Status Code Checks with Playwright

A data-driven test checks many codes in a few lines. Use maxRedirects: 0 to assert a redirect itself instead of following it.

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

const BASE = 'https://sqatools.in/wp-json/sqa-api/v1';

const cases = [
  { name: 'existing user',      path: '/users/1',     expected: 200 },
  { name: 'missing user',       path: '/users/999',   expected: 404 },
  { name: 'non-numeric id',     path: '/users/abc',   expected: 400 },
  { name: 'page size too big',  path: '/users?per_page=51', expected: 400 },
  { name: 'no credentials',     path: '/basic/profile',     expected: 401 },
  { name: 'service down',       path: '/status/503',  expected: 503 },
];

for (const c of cases) {
  test(`GET ${c.path} -> ${c.expected} (${c.name})`, async ({ request }) => {
    const res = await request.get(`${BASE}${c.path}`);
    expect(res.status()).toBe(c.expected);
  });
}

test('redirect is 302 when not followed', async ({ request }) => {
  const res = await request.get(`${BASE}/redirect`, { maxRedirects: 0 });
  expect(res.status()).toBe(302);
  expect(res.headers()['location']).toBeTruthy();
});

test('503 tells the client when to retry', async ({ request }) => {
  const res = await request.get(`${BASE}/status/503`);
  expect(res.headers()['retry-after']).toBe('10');
});

Note: res.ok() is true only for 200-299. Playwright does not throw on 4xx/5xx by default, which is what you want for negative tests.

How to Report a Wrong Status Code

A good bug title: “POST /orders returns 500 instead of 422 when quantity is negative”. Include the full request (cURL), the actual and expected status, the response body, the trace or request id header and the environment. Developers fix these fast when they can replay the request.

Advertisement

Interview Questions: HTTP Status Codes

What is the difference between 401 and 403?

401 Unauthorized means the request is not authenticated: credentials are missing, invalid or expired, and the client should log in. 403 Forbidden means the client is authenticated but does not have permission for this action or resource.

What is the difference between 400 and 422?

400 Bad Request means the server cannot parse or understand the request, such as malformed JSON or an invalid parameter format. 422 Unprocessable Content means the request is well-formed but fails business validation, such as an invalid email or an out-of-range age.

Which status code should a successful POST return?

201 Created when a new resource is created, with a Location header pointing to it. 200 OK is acceptable for POST actions that don’t create a resource (login, search), and 202 Accepted for asynchronous processing.

What is the difference between 200 and 204?

Both mean success. 200 OK returns a body; 204 No Content returns no body, commonly used for DELETE or updates where nothing needs to be returned.

What is the difference between 301 and 302?

301 is a permanent redirect: clients and search engines should update to the new URL. 302 is temporary: keep using the original URL. Use 307/308 when the method and body must be preserved.

When does an API return 304 Not Modified?

When the client sends a conditional request (If-None-Match with an ETag or If-Modified-Since) and the resource has not changed. The server returns 304 with no body, and the client uses its cached copy.

What is the difference between 502, 503 and 504?

502 Bad Gateway: the gateway received an invalid response from the upstream service. 503 Service Unavailable: the service is down or overloaded, ideally with Retry-After. 504 Gateway Timeout: the upstream service did not respond in time.

Is a 500 error always a bug?

From a tester’s point of view, yes. A 500 means an unhandled server failure. If it is caused by client input, it should have been a 4xx validation error; if it is caused by an internal problem, it needs fixing and should not expose stack traces.

What status code is returned when rate limits are exceeded?

429 Too Many Requests, ideally with a Retry-After header and rate limit headers such as X-RateLimit-Limit and X-RateLimit-Remaining.

An API returns 200 with an error message in the body. What do you do?

Log it as a defect: the status code should reflect the result (for example 400, 401 or 422). Explain the impact: monitoring misses failures, clients treat errors as success and caches may store failed responses.

What is 409 Conflict used for?

When a request conflicts with the current state of the resource, such as registering an email that already exists, booking a seat that was just taken or deleting a record that other data depends on.

Advertisement
View the full API testing syllabus

HTTP Methods Explained: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS

HTTP Methods Explained: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS

HTTP methods are the verbs of an API: they tell the server what you want to do with a resource. Mix them up and you get bugs like a “GET” that deletes data or a retry that charges a customer twice. In this lesson you will learn all seven methods testers use, the difference between PUT and PATCH, what “safe” and “idempotent” really mean, and you will run each method on a live object you create yourself.

Quick answerGET reads data, POST creates a new resource, PUT replaces a resource completely (or creates it at a known URL), PATCH updates only some fields, DELETE removes a resource, HEAD returns only the headers of a GET, and OPTIONS lists the methods an endpoint allows. GET, HEAD and OPTIONS are safe (no changes); GET, HEAD, OPTIONS, PUT and DELETE are idempotent (repeating them gives the same result); POST and PATCH are not idempotent.
Advertisement

Real-Life Example: Managing Your Address Book in a Shopping App

Every method in one screen Opening “My addresses” sends GET /addresses. Adding a new office address sends POST /addresses. Editing the whole address form and saving sends PUT /addresses/7. Only marking it as “default” sends PATCH /addresses/7 with {"is_default": true}. Removing it sends DELETE /addresses/7.

This mapping of methods to actions is called CRUD: Create (POST), Read (GET), Update (PUT/PATCH) and Delete (DELETE).

All HTTP Methods at a Glance

MethodPurposeHas body?SafeIdempotentTypical success code
GETRead a resource or listNoYesYes200 OK
POSTCreate a new resource / trigger an actionYesNoNo201 Created (or 200/202)
PUTReplace the whole resource, or create at a known idYesNoYes200 OK / 201 Created / 204
PATCHPartial updateYesNoNot guaranteed200 OK / 204
DELETERemove a resourceUsually noNoYes204 No Content / 200
HEADSame as GET but headers onlyNoYesYes200 OK
OPTIONSWhich methods are allowed (also CORS pre-flight)NoYesYes200 / 204

Two rarer methods: TRACE (echoes the request, should be disabled in production for security) and CONNECT (used by proxies for HTTPS tunnels).

Advertisement

GET: Read Data

GET retrieves data and must never change anything on the server. Parameters go in the URL path or query string.

GEThttps://sqatools.in/wp-json/sqa-api/v1/users?role=admin&sort=age&order=desc
curl -i \
  "https://sqatools.in/wp-json/sqa-api/v1/users?role=admin&sort=age&order=desc"

Test ideas: correct data and count; filters and sorting; 404 for a missing id; 400 for an invalid id (/users/abc); calling it twice changes nothing; sensitive data not exposed; response time.

Real bug pattern A GET link like /unsubscribe?user=42 or /orders/9/cancel that changes data is dangerous: browsers prefetch links, crawlers follow them and caches replay them. Testers should flag any GET that modifies state.

POST: Create a New Resource

POST sends data in the body; the server decides the new id. A correct create returns 201 Created and a Location header.

POSThttps://sqatools.in/wp-json/sqa-api/v1/objects
curl -i \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"name":"Office address","data":{"city":"Pune","pin":"411001"},"ttl":300}' \
  "https://sqatools.in/wp-json/sqa-api/v1/objects"

Test ideas: 201 + Location; body echoes what you sent; required fields missing → 422; extra unknown fields; client trying to set the id (the practice API rejects it with 422); duplicate submission.

Why POST is not idempotent Press “Pay” twice on a slow network and two POST /payments requests may arrive, charging the customer twice. Payment APIs (Razorpay, Stripe) solve it with an Idempotency-Key header: the same key returns the first result instead of creating a second payment. Testing duplicate POSTs is a must for any money-related API.
Advertisement

PUT: Replace (or Create at a Known URL)

PUT sends the complete new version of a resource to its URL. Any field you leave out is removed or reset. If the resource does not exist, many APIs create it (called an upsert).

On the practice API you choose the id. The first PUT returns 201 Created; repeating the same PUT returns 200 OK with the same content, which is what idempotent means.

PUThttps://sqatools.in/wp-json/sqa-api/v1/objects/my-address-01
curl -i \
  -X PUT \
  -H "Content-Type: application/json" \
  -d '{"name":"Home address","data":{"city":"Mumbai","pin":"400001"},"ttl":300}' \
  "https://sqatools.in/wp-json/sqa-api/v1/objects/my-address-01"

Test ideas: full replacement (omitted fields disappear); name missing → 422 (PUT needs the full representation); id in body different from id in URL → 422; repeat the call → same state; version increments.

PATCH: Update Only Some Fields

PATCH sends only the fields that change. The practice API uses JSON Merge Patch rules: fields you send are merged in, and a field set to null is removed.

curl -i -X PATCH "https://sqatools.in/wp-json/sqa-api/v1/objects/my-address-01" \
  -H "Content-Type: application/json" \
  -d '{"data":{"pin":"400002"}}'

Result: city stays “Mumbai”, pin becomes “400002”, version goes up by 1, and the ETag changes from "v1" to "v2".

Test ideas: only sent fields change; null removes a key; empty body {} → 422 “nothing to update”; PATCH on a missing id → 404; read-only fields (id, created_at) cannot be patched.

Advertisement

PUT vs PATCH: The Most Asked Interview Question

PUTPATCH
SendsThe entire resourceOnly the changes
Missing fieldsRemoved or set to defaultLeft unchanged
IdempotentYes, alwaysNot guaranteed (e.g. {"op":"increment"})
Can createYes, at a client-chosen URLUsually no (404 if missing)
Real exampleSaving the whole edit-profile formToggling “dark mode” or “default address”

Example: the stored object is {"name":"Home","data":{"city":"Mumbai","pin":"400001"}}.

  • PUT {"name":"Home","data":{"pin":"400002"}} → city is gone.
  • PATCH {"data":{"pin":"400002"}} → city is kept.

DELETE: Remove a Resource

DELETE removes the resource. The common success code is 204 No Content (empty body).

DELETEhttps://sqatools.in/wp-json/sqa-api/v1/objects/my-address-01
curl -i \
  -X DELETE \
  "https://sqatools.in/wp-json/sqa-api/v1/objects/my-address-01"

Press Send twice. The first call returns 204, the second 404. Is that still idempotent? Yes: idempotency is about the server state (the object is gone either way), not about the status code.

Test ideas: 204 then GET returns 404; deleting twice; deleting without permission → 403; deleting a resource that has children (an order with payments); soft delete vs hard delete; DELETE on read-only resources → 405 (try DELETE /products/101).

Advertisement

HEAD and OPTIONS: The Methods Testers Forget

HEAD

Returns exactly the headers a GET would return, but no body. Used to check if a resource exists, its size (Content-Length) or its version (ETag) without downloading it, for example before downloading a 2 GB file.

HEADhttps://sqatools.in/wp-json/sqa-api/v1/users/1
curl -I \
  "https://sqatools.in/wp-json/sqa-api/v1/users/1"

OPTIONS

Asks which methods are allowed. The answer comes in the Allow header. Browsers also send OPTIONS automatically as a CORS pre-flight before cross-origin PUT/DELETE requests.

OPTIONShttps://sqatools.in/wp-json/sqa-api/v1/users
curl -i \
  -X OPTIONS \
  "https://sqatools.in/wp-json/sqa-api/v1/users"

405 Method Not Allowed

When you use a method an endpoint does not support, the correct answer is 405 with an Allow header listing valid methods. On the practice API, POST /users returns: “This endpoint supports GET, HEAD only.” A 404 or 500 here would be a bug.

Advertisement

Safe vs Idempotent, Explained Simply

  • Safe = read-only. Calling it does not change data. (GET, HEAD, OPTIONS)
  • Idempotent = calling it once or 10 times leaves the server in the same state. (All safe methods + PUT + DELETE)
Lift button analogy Pressing the lift call button 5 times still calls the lift once: idempotent. Ordering “one coffee” 5 times gets you 5 coffees: not idempotent (that’s POST).

Why testers care: networks fail, and clients and gateways retry. Retrying idempotent requests is safe; retrying POST without an idempotency key can create duplicates.

All Methods in One Playwright Test

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

const BASE = 'https://sqatools.in/wp-json/sqa-api/v1';

test('HTTP methods on one object', async ({ request }) => {
  const id = `pw-${Date.now()}`;
  const url = `${BASE}/objects/${id}`;

  // PUT creates (201), PUT again is idempotent (200, same data)
  const body = { name: 'Home', data: { city: 'Mumbai', pin: '400001' }, ttl: 120 };
  expect((await request.put(url, { data: body })).status()).toBe(201);
  expect((await request.put(url, { data: body })).status()).toBe(200);

  // PATCH changes one field and keeps the rest
  const patched = await (await request.patch(url, { data: { data: { pin: '400002' } } })).json();
  expect(patched.data).toEqual({ city: 'Mumbai', pin: '400002' });

  // HEAD: headers only, no body
  const head = await request.head(url);
  expect(head.status()).toBe(200);
  expect((await head.body()).length).toBe(0);

  // DELETE twice: 204 then 404 (state is the same: gone)
  expect((await request.delete(url)).status()).toBe(204);
  expect((await request.delete(url)).status()).toBe(404);
});

test('unsupported method returns 405 with Allow header', async ({ request }) => {
  const res = await request.post(`${BASE}/users`, { data: {} });
  expect(res.status()).toBe(405);
  expect(res.headers()['allow']).toBeTruthy();
});
Advertisement

Interview Questions: HTTP Methods

What is the difference between PUT and PATCH?

PUT replaces the entire resource with the representation you send, so omitted fields are removed, and it is idempotent. PATCH applies a partial update, changing only the fields you send, and is not guaranteed to be idempotent.

What is the difference between GET and POST?

GET reads data, sends parameters in the URL, is safe, idempotent and cacheable. POST sends data in the body to create a resource or trigger processing, changes server state and is not idempotent. Sensitive data should never go in GET query strings because URLs are logged.

What does idempotent mean? Which methods are idempotent?

An idempotent request leaves the server in the same state whether it is sent once or many times. GET, HEAD, OPTIONS, PUT and DELETE are idempotent; POST is not and PATCH is not guaranteed to be.

DELETE returns 204 the first time and 404 the second. Is it still idempotent?

Yes. Idempotency refers to the server state, not the response code. After either call the resource does not exist.

What is the difference between PUT and POST?

POST creates a resource at a URL chosen by the server and is not idempotent. PUT creates or replaces a resource at a URL chosen by the client and is idempotent.

What is the use of the HEAD method?

HEAD returns the same headers as GET without the body. It is used to check existence, size, content type or ETag of a resource without downloading it.

What is the use of the OPTIONS method?

OPTIONS returns the allowed methods for a resource in the Allow header and is used by browsers as a CORS pre-flight request before cross-origin calls.

What status code should an API return for an unsupported method?

405 Method Not Allowed, with an Allow header listing the supported methods.

Can a GET request have a body?

The HTTP specification does not define meaning for a GET body, and many servers, proxies and tools ignore or reject it. APIs should use query parameters for GET; if you see an API requiring a GET body, flag it as a design risk.

How do you prevent duplicate orders when a POST is retried?

Use an Idempotency-Key header generated by the client for each logical operation; the server stores the first result for that key and returns it for retries. Testers verify that sending the same key twice creates only one order.

Advertisement
View the full API testing syllabus

Types of API Testing: 12 Types Explained with Real Examples

Types of API Testing: 12 Types Explained with Real Examples

“API testing” is not one activity. A payment API that returns the right amount can still leak card data, crash at 2,000 users per second, or break the Android app because a field was renamed. In this lesson you will learn the 12 types of API testing used in real projects, each with a real-life scenario, a concrete test on the free SQA Tools practice API and the tools teams use for it.

Quick answerThe main types of API testing are: smoke, functional, negative (validation), integration, end-to-end workflow, contract, security, performance and load, reliability (resilience), regression, fuzz and compatibility (versioning) testing. Functional and negative testing check the business rules, contract testing protects consumers from breaking changes, security testing protects data, and performance testing proves the API stays fast under real traffic.
Advertisement

The Real-Life Scenario We Will Use

An online electronics store Customers browse products, place orders and pay. The backend exposes APIs such as GET /products, POST /orders, POST /auth/login. The mobile app, website, warehouse system and delivery partner all depend on these APIs. A single bug can cost real money, so the QA team runs many types of API testing at different stages.

The practice API mirrors this store: it has users, products, orders, login tokens, validation rules and rate limits, so every type below has a test you can actually run.

1. Smoke Testing

A tiny, fast set of checks that answers one question: is the API up and basically working after a deployment? If smoke fails, there is no point running the other 2,000 tests.

Real example: right after a release at 2 AM, a pipeline calls the health endpoint and one key read endpoint.

GEThttps://sqatools.in/wp-json/sqa-api/v1/health
curl -i \
  "https://sqatools.in/wp-json/sqa-api/v1/health"

Checks: 200 status, "status": "ok", response time under 1 second. Tools: Postman monitor, Playwright test tagged @smoke, uptime monitors.

2. Functional Testing

Verifies that each endpoint does what the requirement says, with valid input. This is the bulk of API testing.

Real example: requirement “Filter products by category” means GET /products?category=books must return only books.

GEThttps://sqatools.in/wp-json/sqa-api/v1/products?category=books
curl -i \
  "https://sqatools.in/wp-json/sqa-api/v1/products?category=books"

Checks: status 200; every item has category = "books"; count matches; prices are numbers; sorting works as documented.

Advertisement

3. Negative and Validation Testing

Sends invalid, missing, out-of-range or wrongly typed data and checks the API rejects it gracefully: correct 4xx code, useful message, no crash, no data saved.

Real example: a signup form sends an empty body. The API should list every missing field in one response, not fail with 500.

POSThttps://sqatools.in/wp-json/sqa-api/v1/validate/user
curl -i \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{}' \
  "https://sqatools.in/wp-json/sqa-api/v1/validate/user"

The practice API answers 422 with three field errors (name, email, age). Other negative cases: age as a string, age 17 and 101 (boundaries), invalid email, malformed JSON (400), wrong Content-Type (415), body over 10 KB (413).

Rule of thumb In real projects, negative tests usually outnumber positive tests by 2 to 3 times. Most production bugs and security issues hide in the inputs nobody expected.

4. Integration Testing

Checks that two or more components work together correctly: API + database, service A + service B, your app + a third-party API.

Real example: when an order is placed, the order service must call the inventory service so stock drops by the ordered quantity. Test: read stock, place order, read stock again.

On the practice API, the nested resource GET /users/1/orders checks that user and order data are correctly linked: every order returned must have user_id = 1.

Advertisement

5. End-to-End (Workflow) Testing

Chains several API calls in the order a real user would make them, passing data from one response into the next request.

Real example: Login → search product → add to cart → place order → pay → check order status “paid”.

import { test, expect } from '@playwright/test';
const BASE = 'https://sqatools.in/wp-json/sqa-api/v1';

test('workflow: create, update, verify, delete', async ({ request }) => {
  const created = await (await request.post(`${BASE}/objects`, {
    data: { name: 'Cart #1', data: { items: 1 }, ttl: 120 },
  })).json();

  const patched = await request.patch(`${BASE}/objects/${created.id}`, { data: { data: { items: 3 } } });
  expect(patched.status()).toBe(200);
  expect((await patched.json()).version).toBe(2);

  const read = await (await request.get(`${BASE}/objects/${created.id}`)).json();
  expect(read.data.items).toBe(3);

  expect((await request.delete(`${BASE}/objects/${created.id}`)).status()).toBe(204);
  expect((await request.get(`${BASE}/objects/${created.id}`)).status()).toBe(404);
});

6. Contract Testing

Verifies that the API’s structure (field names, data types, required fields, status codes) matches the agreed contract, so consumers like the mobile app do not break.

Real example: a backend developer renames price to amount. All functional tests still pass on the backend, but the Android app shows “Rs null”. A contract test against the JSON Schema catches it in CI before release.

The practice API publishes its schema: GET /schema/user returns a JSON Schema with "additionalProperties": false. Tools: JSON Schema validators (Ajv, Zod), Pact for consumer-driven contracts, OpenAPI diff tools.

Advertisement

7. Security Testing

Checks authentication, authorization, data exposure, injection and abuse protection. The OWASP API Security Top 10 is the standard checklist.

CheckExample testExpected
No credentialsGET /basic/profile without Authorization401 + WWW-Authenticate
Wrong roleViewer token on POST /token/objects403
Tampered tokenChange one character of a JWT401
BOLA / IDORUser A requests user B’s order by id403 or 404, never the data
InjectionSend ' OR 1=1 -- or <script> as a nameStored as plain text, not executed
Data exposureInspect every responseNo passwords, tokens or internal fields
GEThttps://sqatools.in/wp-json/sqa-api/v1/basic/profile
curl -i \
  "https://sqatools.in/wp-json/sqa-api/v1/basic/profile"

8. Performance and Load Testing

Measures response time and throughput under normal and peak traffic. Related types:

  • Load testing: expected peak, e.g. 500 requests/second during a sale.
  • Stress testing: increase until it breaks, to find the limit and how it fails.
  • Spike testing: sudden jump, e.g. traffic x10 when a flash sale opens at 12:00.
  • Soak (endurance) testing: steady load for hours to find memory leaks.

Real example: Big Billion Day style sales. The product API must stay under 300 ms at the 95th percentile with 5x normal traffic.

The practice API has /delay/{seconds} to simulate slow responses and /rate-limit, which returns 429 Too Many Requests with Retry-After on the 6th call in a minute. Tools: k6, JMeter, Gatling, Artillery; Playwright for simple SLA assertions.

Advertisement

9. Reliability and Resilience Testing

Checks how the API and its clients behave when things go wrong: timeouts, slow dependencies, 503 responses, retries and circuit breakers.

Real example: the SMS provider is down. Does signup still complete (OTP queued for retry) or does the whole API return 500?

Practise with GET /status/503 (returns Retry-After: 10) and GET /delay/5 with a 2-second client timeout. Your client should give up cleanly and retry with back-off.

10. Regression Testing

Re-runs existing API tests after every code change to make sure nothing that used to work is now broken. This is where automation pays off: 1,000 API tests can run in a few minutes on every pull request in GitHub Actions or Jenkins.

Real example: a developer optimises the pricing query. The regression suite catches that orders with a coupon now return total 0.

Advertisement

11. Fuzz Testing

Sends large volumes of random, malformed or unexpected input to discover crashes and unhandled errors. Any 5xx during fuzzing is a bug.

Real example: sending a 1 MB string, emojis, null bytes, nested JSON 1,000 levels deep or numbers like 1e309 to the product search API. Tools: RESTler, Schemathesis (generates tests from OpenAPI), Burp Suite Intruder.

12. Compatibility and Versioning Testing

Ensures new API versions do not break existing clients and that old versions keep working until they are retired.

Real example: 30% of users never update the app. When /v2/orders launches, /v1/orders must keep the old response shape. Testers run the v1 suite against the new build and check deprecation headers.

Summary Table: Types of API Testing

TypeQuestion it answersWhen it runsCommon tools
SmokeIs it alive?Every deploymentPostman, Playwright
FunctionalDoes it meet requirements?Every featurePostman, Playwright, REST Assured
NegativeDoes it reject bad input safely?Every featureSame + data-driven files
IntegrationDo components work together?Build / stagingPlaywright, Postman
End-to-endDoes a real user journey work?Staging, nightlyPlaywright, Postman flows
ContractDid the structure change?Every pull requestAjv, Zod, Pact
SecurityIs data protected?Each release, pen-testsOWASP ZAP, Burp, Playwright
PerformanceIs it fast at scale?Before big releases/salesk6, JMeter, Gatling
ReliabilityDoes it fail gracefully?Staging, chaos daysMocks, fault injection
RegressionDid we break old features?Every commitCI + automation suite
FuzzCan random input crash it?PeriodicallySchemathesis, RESTler
CompatibilityDo old clients still work?New versionsVersioned test suites
Advertisement

Interview Questions: Types of API Testing

What types of API testing have you performed?

Name 4 to 6 types with a concrete example each: functional and negative testing of order APIs, contract testing with JSON Schema in CI, security checks for 401/403 and IDOR, smoke tests after each deployment and load testing with k6 before a sale. Concrete examples matter more than a long list.

What is the difference between functional and non-functional API testing?

Functional testing verifies what the API does (correct data, rules, status codes). Non-functional testing verifies how well it does it: performance, security, reliability, scalability and usability of error messages.

What is contract testing and why is it important?

Contract testing checks that the API’s request and response structure matches the agreement between provider and consumers. It catches breaking changes such as renamed fields or changed data types before they reach mobile apps or partner systems.

What is the difference between integration testing and end-to-end API testing?

Integration testing checks the interaction between specific components, such as the order service and the inventory service. End-to-end testing follows a complete business journey across all components, such as login to payment confirmation.

What is the difference between load, stress and spike testing?

Load testing uses the expected peak traffic; stress testing increases traffic beyond the limit to see where and how the system breaks; spike testing applies a sudden large jump in traffic to check the system scales and recovers.

What would you include in an API smoke suite?

A health check, login, one key read endpoint and one key write endpoint per critical service, with simple status and response time assertions. It should run in under a minute after every deployment.

What is fuzz testing?

Fuzz testing sends random or malformed inputs at high volume to find crashes, 5xx errors and unhandled exceptions. Tools such as Schemathesis generate fuzz cases automatically from an OpenAPI specification.

How do you test API backward compatibility?

Run the existing consumer tests or contract tests of the old version against the new build, verify no required fields were removed or changed in type, check deprecation headers, and confirm old versions remain available for the agreed period.

Why should negative tests outnumber positive tests?

There is usually one correct way to call an endpoint but many ways to call it wrongly: missing fields, wrong types, boundaries, invalid formats, wrong roles and malicious input. Most production bugs and vulnerabilities live in these paths.

What is reliability or resilience testing for APIs?

Testing how the API behaves when dependencies fail or slow down: timeouts, retries with back-off, circuit breakers, 503 with Retry-After and graceful degradation instead of complete failure.

Advertisement
View the full API testing syllabus

REST vs SOAP vs GraphQL: Differences Every Tester Should Know

REST vs SOAP vs GraphQL: Differences Every Tester Should Know

“What is the difference between REST and SOAP?” has been asked in almost every API testing interview for over a decade, and GraphQL is now added to it. In this lesson you will see one real requirement, “get the balance and last two transactions of a bank customer”, built three ways, so the differences become obvious instead of memorised. Then you will learn how your test cases change for each style.

Quick answerREST is an architectural style that uses many resource URLs, HTTP methods and usually JSON. SOAP is a strict XML protocol with a WSDL contract, one endpoint per service and built-in WS-Security. GraphQL is a query language with a single endpoint where the client asks for exactly the fields it needs. REST suits most web and mobile apps, SOAP suits enterprise systems that need strict contracts and transactions (banking, insurance), and GraphQL suits apps with complex, changing data needs.
Advertisement

One Requirement, Three APIs

The mobile banking app needs: customer name, account balance and the last 2 transactions. Let’s see how each API style delivers it.

REST: several resource URLs

GET /v1/customers/42
GET /v1/accounts/ACC-4521
GET /v1/accounts/ACC-4521/transactions?limit=2
{ "data": { "id": "ACC-4521", "type": "savings", "balance": 18400.50,
            "currency": "INR", "branch": "Pune Camp", "ifsc": "SQAT0000123",
            "opened_on": "2019-06-11", "nominee": "...", "...": "many more fields" } }

Three round trips, and the account call returns many fields the screen never shows (over-fetching). Getting both pieces of data with one call isn’t possible (under-fetching), unless the team builds a custom endpoint.

SOAP: one operation, XML envelope

POST /CoreBankingService HTTP/1.1
Content-Type: text/xml; charset=utf-8
SOAPAction: "GetAccountSummary"

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:cb="http://bank.example.com/core">
  <soapenv:Header><wsse:Security>...signed token...</wsse:Security></soapenv:Header>
  <soapenv:Body>
    <cb:GetAccountSummary>
      <cb:CustomerId>42</cb:CustomerId>
      <cb:TxnCount>2</cb:TxnCount>
    </cb:GetAccountSummary>
  </soapenv:Body>
</soapenv:Envelope>

Always POST, always XML, operation defined in the WSDL. Verbose, but every field, type and error is strictly defined.

GraphQL: one query, exact fields

POST /graphql
{
  customer(id: 42) {
    name
    account { balance currency }
    transactions(last: 2) { date amount description }
  }
}

One request, and the response contains exactly those fields and nothing else.

Advertisement

REST vs SOAP vs GraphQL: Comparison Table

FeatureRESTSOAPGraphQL
What it isArchitectural styleProtocol (W3C standard)Query language + runtime
Data formatJSON mostly (also XML, text)XML onlyJSON
EndpointsMany (one per resource)One per service, many operationsUsually one (/graphql)
HTTP methodsGET, POST, PUT, PATCH, DELETEMostly POSTMostly POST (GET for queries possible)
ContractOpenAPI / Swagger (optional)WSDL + XSD (mandatory)Schema (SDL), strongly typed
Error reportingHTTP status codes + error bodySOAP Fault element (often HTTP 500)errors array, often with HTTP 200
CachingEasy (HTTP caching, ETag)HardHard (single POST endpoint), needs client caching
SecurityHTTPS + OAuth 2.0/JWTWS-Security (signing, encryption) + HTTPSHTTPS + OAuth/JWT, plus query depth limits
Payload sizeMediumLarge (XML envelope)Small (only requested fields)
Learning curveEasySteeperMedium
Typical usersMost web and mobile appsBanks, insurance, telecom, governmentGitHub, Shopify, Meta, data-rich dashboards
Testing toolsPostman, Playwright, REST AssuredSoapUI, ReadyAPI, PostmanPostman, Playwright, Insomnia

REST in Detail (with a Live Example)

REST follows six constraints: client-server, stateless, cacheable, uniform interface, layered system and (optional) code on demand. For testers the important ideas are: resources as URLs, methods as actions and status codes as results.

Request the same user in JSON (default) and, with content negotiation, in XML. REST lets one resource have several representations:

GEThttps://sqatools.in/wp-json/sqa-api/v1/users/1
curl -i \
  -H "Accept: application/xml" \
  "https://sqatools.in/wp-json/sqa-api/v1/users/1"

Change the Accept header to text/csv and the API replies 406 Not Acceptable, a great negative test.

Advertisement

SOAP in Detail

A SOAP message has four parts:

  • Envelope (mandatory): root element that marks the XML as a SOAP message.
  • Header (optional): security tokens, transaction ids, routing.
  • Body (mandatory): the operation and its parameters, or the response.
  • Fault (inside Body, on errors): faultcode, faultstring and detail.
<soap:Body>
  <soap:Fault>
    <faultcode>soap:Client</faultcode>
    <faultstring>Invalid account number</faultstring>
    <detail><cb:ErrorCode>ACC-404</cb:ErrorCode></detail>
  </soap:Fault>
</soap:Body>
Real-life example: insurance policy issue An insurance company’s agent portal calls a SOAP IssuePolicy operation. WS-Security signs the message, so it cannot be changed in transit. WS-AtomicTransaction makes sure payment capture and policy creation both succeed or both roll back. This is exactly why regulated industries stay on SOAP.

You will test SOAP hands-on in the SoapUI lessons of Module 4.

GraphQL in Detail

GraphQL has three operation types:

  • Query: read data.
  • Mutation: create, update or delete data.
  • Subscription: real-time updates, usually over WebSocket.
// Partial success: HTTP 200, but one field failed
{
  "data": { "customer": { "name": "Asha Verma", "transactions": null } },
  "errors": [
    { "message": "Not authorised to view transactions", "path": ["customer", "transactions"] }
  ]
}

This is the biggest trap for testers coming from REST: a 200 does not mean success. Always assert that errors is absent (or contains what you expect).

Advertisement

How Test Cases Differ for Each Style

Test areaRESTSOAPGraphQL
PositiveEach method on each resourceEach WSDL operationEach query and mutation, different field selections
Validation400/422 with field errorsSOAP Fault, XSD validationErrors array, type errors from schema
ContractJSON Schema / OpenAPI diffWSDL/XSD complianceSchema diff, deprecated fields
SecurityAuth, BOLA, rate limitWS-Security, XML injection, XXEField-level auth, depth/complexity limits, introspection off
PerformancePer endpointPer operation, payload sizeExpensive nested queries, N+1 problem
AssertionsJSON path on bodyXPath / XQueryJSON path on data and errors

Playwright Example: Testing REST and GraphQL the Same Way

Playwright’s request fixture can call any HTTP API, so the same framework covers REST, GraphQL and even SOAP (as a POST with an XML body).

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

test('REST: content negotiation returns XML', async ({ request }) => {
  const res = await request.get('https://sqatools.in/wp-json/sqa-api/v1/users/1', {
    headers: { Accept: 'application/xml' },
  });
  expect(res.status()).toBe(200);
  expect(res.headers()['content-type']).toContain('application/xml');
  expect(await res.text()).toContain('<name>Asha Verma</name>');
});

test('GraphQL: assert data AND errors', async ({ request }) => {
  const res = await request.post('https://example.com/graphql', {
    data: { query: '{ user(id: 1) { name email } }' },
  });
  expect(res.status()).toBe(200);
  const body = await res.json();
  expect(body.errors).toBeUndefined();          // the important GraphQL check
  expect(body.data.user.name).toBe('Asha Verma');
});

test('SOAP: post an XML envelope', async ({ request }) => {
  const envelope = `<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
      xmlns:tem="http://tempuri.org/"><soapenv:Body>
      <tem:Add><tem:intA>5</tem:intA><tem:intB>7</tem:intB></tem:Add>
    </soapenv:Body></soapenv:Envelope>`;
  const res = await request.post('http://www.dneonline.com/calculator.asmx', {
    headers: { 'Content-Type': 'text/xml; charset=utf-8', SOAPAction: '"http://tempuri.org/Add"' },
    data: envelope,
  });
  expect(res.status()).toBe(200);
  expect(await res.text()).toContain('<AddResult>12</AddResult>');
});

The GraphQL URL above is a placeholder; replace it with your project’s endpoint. The SOAP calculator is a free public demo service.

Advertisement

When to Choose Which (Decision Guide)

  • Choose REST for public APIs, CRUD-style apps, mobile backends and anything that benefits from HTTP caching.
  • Choose SOAP when a partner or regulator requires it, or you need WS-Security signing and distributed transactions.
  • Choose GraphQL when many different clients (web, Android, iOS, smart TV) need different shapes of the same data and you want to avoid many custom endpoints.
Interview tip Don’t say “REST is better than SOAP”. Say “they solve different problems”, give one real example of each from your project or industry, and mention one testing difference (status codes vs SOAP Faults, or the GraphQL 200-with-errors trap). That answer stands out.
Advertisement

Common Myths

  • “REST always uses JSON.” No, REST can return XML, CSV or anything; the practice API returns XML when asked.
  • “SOAP is dead.” No, it still runs core systems in banking, insurance, airlines and government.
  • “GraphQL replaces REST.” Most companies run both; GraphQL often sits in front of REST services.
  • “SOAP only works over HTTP.” It can also use SMTP, JMS and other transports.
Advertisement

Interview Questions: REST vs SOAP vs GraphQL

What is the difference between REST and SOAP?

REST is an architectural style using resource URLs, HTTP methods, status codes and usually JSON; it is lightweight and cacheable. SOAP is an XML-based protocol with a mandatory WSDL contract, an envelope structure, SOAP Faults for errors and WS-Security for message-level security. REST suits web and mobile apps; SOAP suits enterprise systems needing strict contracts and transactions.

Can REST use XML?

Yes. REST is format-independent. The client asks for a format with the Accept header and the server answers with Content-Type. JSON is just the most common choice.

What is a SOAP Fault?

The standard error element inside the SOAP Body, containing faultcode, faultstring and optional detail. It is usually returned with HTTP status 500. Testers assert on the fault code and message using XPath.

What are over-fetching and under-fetching?

Over-fetching is getting more fields than you need; under-fetching is needing several calls to get all the data for one screen. GraphQL solves both by letting the client request exactly the fields it needs in one query.

Why is GraphQL harder to cache than REST?

REST GET requests have unique URLs that browsers, CDNs and proxies can cache. GraphQL usually sends every query as a POST to one URL, so HTTP caching doesn’t work out of the box; clients use their own normalised caches or persisted queries.

What are the three operation types in GraphQL?

Query to read data, mutation to change data and subscription to receive real-time updates.

How do you validate a SOAP response?

Check the HTTP status, validate it against the XSD in the WSDL, assert values with XPath, check that no SOAP Fault is present for positive cases, and verify the fault code and message for negative cases. SoapUI provides all of these assertions.

Which is more secure, REST or SOAP?

Neither is automatically more secure. SOAP has built-in WS-Security for message-level signing and encryption. REST relies on HTTPS plus OAuth 2.0 or JWT, which is secure when implemented correctly. Security depends on the implementation and must be tested.

What is the main testing trap in GraphQL?

Errors often come back with HTTP 200 inside an errors array, and partial data can be returned. Tests that only check the status code will pass while the feature is broken.

Which tool would you use to test SOAP services and why?

SoapUI (or ReadyAPI), because it imports the WSDL, generates request templates for every operation, and provides XPath, XSD and SOAP Fault assertions plus data-driven testing. Postman can also send SOAP requests but with less WSDL support.

Advertisement
View the full API testing syllabus

Types of APIs: REST, SOAP, GraphQL, gRPC, WebSocket and Webhooks

Types of APIs: REST, SOAP, GraphQL, gRPC, WebSocket and Webhooks

“Which types of APIs have you tested?” is one of the most common API testing interview questions, and a weak answer instantly shows a lack of real experience. In this lesson you will learn both ways to classify APIs (by who can use them and by how they are built), see a real product that uses each type, and learn what a tester must check differently for each one.

Quick answerAPIs are classified in two ways. By access: Open (public), Partner, Internal (private) and Composite APIs. By architecture or protocol: REST, SOAP, GraphQL, gRPC, WebSocket and Webhooks (plus older RPC styles such as JSON-RPC and XML-RPC). REST is the most common in web and mobile apps, SOAP is still common in banking and insurance, GraphQL in data-heavy apps, gRPC between microservices, WebSocket for real-time updates and webhooks for event notifications.
Advertisement

Classification 1: Types of APIs by Access

1. Open APIs (Public APIs)

Available to any developer, sometimes with a free API key. They usually have strict rate limits.

Real-life examples OpenWeatherMap (weather data in travel apps), Google Maps Platform (maps inside Ola or Zomato), GitHub REST API, and the SQA Tools practice API you use in this course.

What to test: rate limiting (429 Too Many Requests), API key validation, clear documentation matches behaviour, backward compatibility between versions, and behaviour under abuse such as huge page sizes.

2. Partner APIs

Shared only with business partners under a contract. Access is given after onboarding, often with stronger authentication (OAuth 2.0 client credentials, mutual TLS, IP allow-listing).

Real-life examples Razorpay or PayU payment gateway APIs used by online stores; airline inventory APIs used by MakeMyTrip; courier APIs (Delhivery, Blue Dart) used by e-commerce sellers to create shipments and track parcels.

What to test: contract (field names, formats) exactly as agreed, sandbox vs production behaviour, signature or HMAC validation, idempotency keys (so a retry doesn’t charge a customer twice), and webhook callbacks.

3. Internal APIs (Private APIs)

Used only inside a company, between its own apps and services. Most APIs a tester works on daily are internal.

Real-life example Inside Swiggy, the mobile app calls an internal “restaurant listing” API, which calls internal “menu”, “offers” and “delivery-time” APIs. None of these are open to the public.

What to test: business rules, integration between services, authorization between roles, and data consistency. Don’t assume “internal” means “safe”: internal APIs are a frequent source of data leaks.

4. Composite APIs

One API call that internally triggers several other API calls and returns a combined answer. Often provided by a Backend-for-Frontend (BFF) layer to reduce mobile network calls.

Real-life example When you open an order in the Amazon app, one composite call such as GET /order-summary/123 gathers order details, shipment tracking, payment status and return eligibility from four services.

What to test: partial failures (what if the tracking service is down: error, or a response with tracking missing?), timeouts, correct merging of data, and performance of the whole chain.

Advertisement

Classification 2: Types of APIs by Architecture and Protocol

TypeData formatTransportTypical useReal example
RESTJSON (sometimes XML)HTTP/1.1, HTTP/2Web and mobile appsFlipkart product and cart APIs
SOAPXML only (envelope)HTTP, sometimes JMS/SMTPBanking, insurance, government, telecomCore banking fund transfer, insurance policy issue
GraphQLJSONHTTP (single endpoint)Data-heavy UIs with varying needsGitHub API v4, Shopify Storefront API
gRPCProtocol Buffers (binary)HTTP/2Fast service-to-service callsMicroservices at Netflix, Uber
WebSocketAny (often JSON)Persistent TCP connectionReal-time, two-wayLive cricket scores, stock tickers, chat
WebhookJSONHTTP POST from server to youEvent notificationsRazorpay “payment.captured”, GitHub push event
JSON-RPC / XML-RPCJSON / XMLHTTPCalling remote functions by nameEthereum nodes (JSON-RPC), older CMS systems

REST APIs

REST (Representational State Transfer) is an architectural style, not a protocol. Everything is a resource with a URL (/users/1), and you act on it with HTTP methods (GET, POST, PUT, PATCH, DELETE). It is stateless, cacheable and uses standard status codes.

GEThttps://sqatools.in/wp-json/sqa-api/v1/products/101
curl -i \
  "https://sqatools.in/wp-json/sqa-api/v1/products/101"

What to test in REST: correct methods and status codes, JSON schema, filters and pagination, headers (ETag, caching), authentication, idempotency of PUT and DELETE.

Advertisement

SOAP APIs

SOAP (Simple Object Access Protocol) is a strict, XML-based protocol. Every message is an XML envelope with an optional header and a body. The contract is described in a WSDL file, which tools such as SoapUI read to generate requests automatically.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:bank="http://example.com/bank">
  <soapenv:Header>
    <bank:AuthToken>abc123</bank:AuthToken>
  </soapenv:Header>
  <soapenv:Body>
    <bank:GetBalance>
      <bank:AccountNumber>XXXX4521</bank:AccountNumber>
    </bank:GetBalance>
  </soapenv:Body>
</soapenv:Envelope>
Why banks still use SOAP Built-in standards for security (WS-Security), reliable messaging and transactions, plus a strict contract that both sides must follow. Many core banking, insurance and government systems built 10 to 20 years ago still expose SOAP services, so SoapUI skills remain in demand.

What to test in SOAP: WSDL validity, XML schema (XSD) compliance, SOAP Faults for errors (usually HTTP 500 with a <soap:Fault>), WS-Security headers, and XPath assertions on response values.

GraphQL APIs

GraphQL has a single endpoint (usually POST /graphql). The client writes a query that asks for exactly the fields it needs, so there is no over-fetching or under-fetching.

query {
  user(id: 1) {
    name
    orders(last: 2) { id total status }
  }
}

What to test in GraphQL: queries and mutations, field-level authorization, errors returned inside an errors array (often with HTTP 200!), deeply nested queries that could overload the server (query depth and complexity limits), and introspection being disabled in production.

Advertisement

gRPC APIs

gRPC, created by Google, sends compact binary messages (Protocol Buffers) over HTTP/2. The contract lives in a .proto file. It is much faster than JSON, supports streaming, and is popular for internal microservice traffic.

service PriceService {
  rpc GetPrice (PriceRequest) returns (PriceReply);
}
message PriceRequest { int32 product_id = 1; string pincode = 2; }
message PriceReply  { double price = 1; string currency = 2; }

What to test in gRPC: gRPC status codes (OK, NOT_FOUND, INVALID_ARGUMENT, DEADLINE_EXCEEDED), deadlines and timeouts, streaming behaviour, and backward compatibility of the .proto file. Tools: Postman (gRPC requests), grpcurl, BloomRPC-style clients and k6.

WebSocket APIs

A WebSocket opens one long-lived connection where both sides can send messages at any time. No repeated polling.

Real-life example: live cricket score Cricbuzz-style apps keep a WebSocket open. When a wicket falls, the server pushes {"event":"wicket","score":"145/4"} instantly to millions of phones. The same idea powers Zerodha Kite price ticks and WhatsApp Web messages.

What to test: connection handshake (HTTP 101 Switching Protocols), message order and format, reconnection after network drop, authentication on connect, heartbeat/ping, and load with many simultaneous connections.

Advertisement

Webhooks (Reverse APIs)

With a normal API you call the server. With a webhook, the server calls you when an event happens, by sending an HTTP POST to a URL you registered.

Real-life example: payment confirmation An online store registers https://shop.com/webhooks/razorpay. When a customer’s payment succeeds, Razorpay POSTs a payment.captured event with a signature header. The store verifies the signature and marks the order as paid, even if the customer closed the browser.

What to test: signature verification (reject tampered payloads), duplicate deliveries (the same event twice must not ship two parcels), retries when your endpoint is down, ordering of events, and quick 2xx acknowledgement. Tools such as webhook.site help you capture webhook calls while testing.

Which API Type Should You Learn First?

  1. REST: over 80% of the APIs you will test. Master it first (this course focuses on it).
  2. SOAP with SoapUI, if you target banking, insurance or service companies with enterprise clients.
  3. GraphQL: growing fast in product companies.
  4. WebSocket, webhooks and gRPC: learn the concepts and test approach; tools are similar.
Advertisement

Testing Checklist by API Type

TypeMain toolKey assertionsTypical bug
RESTPostman, PlaywrightStatus, JSON body, schema, headersWrong status code, missing validation
SOAPSoapUIXPath values, XSD, SOAP FaultNamespace mismatch, fault without details
GraphQLPostman, Playwrightdata and errors, field authErrors hidden in 200 responses
gRPCPostman, grpcurlgRPC status, message fieldsBreaking .proto change
WebSocketPostman, PlaywrightMessage content and orderNo reconnect after network drop
Webhookwebhook.site, mock serverSignature, payload, retriesDuplicate event processed twice
Advertisement

Interview Questions: Types of APIs

What are the different types of APIs?

By access: Open/public, Partner, Internal/private and Composite APIs. By architecture: REST, SOAP, GraphQL, gRPC, WebSocket, webhooks and RPC styles such as JSON-RPC and XML-RPC.

Which types of APIs have you tested?

Answer with specifics: for example, “Internal REST APIs for an e-commerce order service using Postman and Playwright, a partner payment gateway API including webhooks, and SOAP services of a banking client in SoapUI.” Mention one interesting bug you found.

What is a composite API?

A single API call that internally calls several other APIs and returns a combined response, often used by a Backend-for-Frontend layer to reduce the number of mobile network calls.

What is a webhook and how is it different from an API?

A webhook is an HTTP callback: the provider sends a POST to your URL when an event happens. With a normal API the client pulls data; with a webhook the server pushes it. Webhooks must be verified with signatures and handled idempotently.

What is WSDL?

Web Services Description Language is an XML document that describes a SOAP service: its operations, message formats, data types and endpoint address. SoapUI imports it to create test requests automatically.

When would you use WebSocket instead of REST?

When the server needs to push frequent real-time updates, such as live scores, stock prices, chat or ride tracking. Polling a REST endpoint every second would waste bandwidth and add delay.

What is gRPC and why is it fast?

gRPC is a remote procedure call framework that uses binary Protocol Buffers over HTTP/2, which gives small messages, multiplexed connections and streaming. It is mostly used for internal service-to-service communication.

Why can GraphQL return 200 OK for an error?

Because a GraphQL request can partly succeed, errors are reported in an errors array in the body while the HTTP status is often 200. Testers must assert on the errors array, not only on the status code.

What is the difference between a public and a partner API from a testing point of view?

Public APIs need strong rate limiting, abuse protection and backward compatibility for unknown consumers. Partner APIs need strict contract testing, stronger authentication, sandbox testing and webhook/signature validation agreed with specific partners.

Is REST a protocol?

No. REST is an architectural style that usually runs over HTTP. SOAP is a protocol with a formal specification.

Advertisement
View the full API testing syllabus

How an API Works: Request, Response and Endpoints Explained

How an API Works: Request, Response and Endpoints Explained

Before you can test an API you need to see exactly what travels between the app and the server. In this lesson we follow one food order from the moment you tap “Place Order” until the confirmation appears, then break every API request and response into its parts: URL, method, headers, body, status code. Every concept is shown on a live endpoint you can call right now.

Quick answerAn API works on a request-response cycle. A client sends an HTTP request (method + URL + headers + optional body) to an endpoint on a server. The server runs business logic, talks to the database and returns a response (status code + headers + body, usually JSON). API testing means checking that every response is correct for every kind of request.
Advertisement

The Client-Server Model in Plain Words

Every API conversation has two sides:

  • Client: whoever asks. It can be a mobile app, a website running in the browser, Postman, a Playwright test, or another backend service.
  • Server: whoever answers. It receives the request, checks who you are, applies business rules, reads or writes the database, and replies.

The client and server can be written in totally different languages. A Swift iPhone app can talk to a Java server, which can talk to a Python pricing service. They understand each other because they agree on the same HTTP protocol and data format (usually JSON).

Real-life example: an ATM The ATM screen is the client. When you ask for Rs 2,000, the ATM sends a request to the bank’s server: “account X wants to withdraw 2000, here is the PIN proof”. The server checks the balance and the daily limit, deducts the money and replies “approved, new balance 18,400” or “declined: insufficient funds”. The ATM never touches the bank database directly. That middle layer of rules is the API.

Step-by-Step: What Happens When You Place a Food Order

  1. You tap Place Order. The app builds a request: POST https://api.foodapp.com/v1/orders with your token in the Authorization header and the items in a JSON body.
  2. DNS converts api.foodapp.com into an IP address.
  3. A secure HTTPS (TLS) connection is opened so nobody on the Wi-Fi can read the data.
  4. An API gateway checks the token and the rate limit, then forwards the request to the order service.
  5. The order service validates the items, asks the pricing service for the total, reserves stock and saves the order in the database.
  6. The server replies 201 Created with the new order id and total.
  7. The app reads the JSON and shows “Order placed! Arriving in 32 minutes.”

As a tester, steps 1 and 6 are what you control and observe. Everything in between is the “black box” you are testing through its API.

Advertisement

Anatomy of an API URL

Take this real endpoint from the SQA Tools practice API:

https://sqatools.in/wp-json/sqa-api/v1/users?role=admin&sort=age&order=desc
PartValueMeaning
SchemehttpsProtocol; HTTPS means encrypted
Host (domain)sqatools.inWhich server to call
Base path/wp-json/sqa-apiWhere this API lives on the server
Version/v1API version, so old apps keep working when v2 arrives
Resource/usersThe “thing” you work with (a noun, plural)
Query string?role=admin&sort=age&order=descOptional filters, sorting and paging

Everything up to and including the version is called the base URL: https://sqatools.in/wp-json/sqa-api/v1. Each resource path added to it, together with a method, is an endpoint.

Endpoint = Method + Path

The same path can be several endpoints, depending on the HTTP method:

EndpointWhat it does
GET /objectsList objects
POST /objectsCreate a new object
GET /objects/{id}Read one object
PUT /objects/{id}Replace it completely
PATCH /objects/{id}Change some fields
DELETE /objects/{id}Delete it

The {id} part is a path parameter. You will study path and query parameters in depth in this lesson.

Advertisement

The 4 Parts of an API Request

1. Method (verb)

Tells the server what you want to do: GET read, POST create, PUT replace, PATCH update, DELETE remove. Full details in HTTP Methods.

2. URL (where)

Base URL + resource path + optional query string.

3. Headers (extra information about the request)

Content-Type: application/json      (the body I am sending is JSON)
Accept: application/json            (please answer in JSON)
Authorization: Bearer eyJhbGciOi... (this is who I am)
X-Request-Id: 7f3c-91aa             (trace id for debugging)

4. Body (payload, the data you send)

Used with POST, PUT and PATCH. GET and DELETE normally have no body.

{
  "name": "Laptop bag",
  "data": { "color": "black", "qty": 1 },
  "ttl": 120
}

The 3 Parts of an API Response

1. Status code

A 3-digit number that summarises the result. 2xx success, 3xx redirect, 4xx your (client) mistake, 5xx server failure. See the complete status code list.

2. Response headers

For example Content-Type, Location (URL of a newly created item), ETag (version for caching), Retry-After, and pagination headers such as X-Total-Count.

3. Response body

The data itself, or an error object. The practice API always uses the same error format, which is good API design and easy to assert:

{
  "error": {
    "status": 404,
    "code": "not_found",
    "message": "User 999 does not exist. Valid ids are 1 to 12."
  }
}
Advertisement

See a Full Request and Response Live

Press Send request to create a temporary object (it deletes itself after 2 minutes). Look at the status 201, the Location header and the ETag header in the result.

POSThttps://sqatools.in/wp-json/sqa-api/v1/objects
curl -i \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"name":"Laptop bag","data":{"color":"black","qty":1},"ttl":120}' \
  "https://sqatools.in/wp-json/sqa-api/v1/objects"

Here is the same conversation written out as raw HTTP, which is how it really looks on the wire:

POST /wp-json/sqa-api/v1/objects HTTP/1.1
Host: sqatools.in
Content-Type: application/json
Accept: application/json

{"name":"Laptop bag","data":{"color":"black","qty":1},"ttl":120}

HTTP/1.1 201 Created
Content-Type: application/json; charset=UTF-8
Location: https://sqatools.in/wp-json/sqa-api/v1/objects/obj_hoeovqif1v
ETag: "v1"

{"id":"obj_hoeovqif1v","name":"Laptop bag","data":{"color":"black","qty":1},
 "version":1,"created_at":"2026-11-12T08:03:29Z","ttl_seconds":120, ...}
Tester’s checklist for this one call Status is 201 (not 200). Location header exists and ends with the returned id. version is 1. name and data match what you sent. A follow-up GET on the Location URL returns the same object. Sending the same body without name returns 422.
Advertisement

Writing the Same Request in Code

cURL

curl -i -X POST "https://sqatools.in/wp-json/sqa-api/v1/objects" \
  -H "Content-Type: application/json" \
  -d '{"name":"Laptop bag","data":{"color":"black","qty":1},"ttl":120}'

The -i flag prints response headers, which testers almost always want to see.

Playwright with TypeScript

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

const BASE = 'https://sqatools.in/wp-json/sqa-api/v1';

test('create an object and read it back', async ({ request }) => {
  // 1. Request: method + URL + headers + body
  const create = await request.post(`${BASE}/objects`, {
    data: { name: 'Laptop bag', data: { color: 'black', qty: 1 }, ttl: 120 },
  });

  // 2. Response: status, headers, body
  expect(create.status()).toBe(201);
  const location = create.headers()['location'];
  const created = await create.json();
  expect(location).toContain(created.id);
  expect(created.version).toBe(1);

  // 3. Prove it was saved: GET the Location URL
  const read = await request.get(location);
  expect(read.ok()).toBeTruthy();
  expect((await read.json()).name).toBe('Laptop bag');
});

Passing an object to data makes Playwright set Content-Type: application/json automatically.

Synchronous vs Asynchronous APIs

Most REST calls are synchronous: you wait and get the result in the same response. Some work takes too long, like generating a 50-page bank statement. Then the API is asynchronous:

  1. POST /statements returns 202 Accepted with a job id.
  2. The client polls GET /statements/jobs/{id} until the status is "done", or the server calls the client back with a webhook.

Testing async APIs means checking the 202, the job status changes, timeouts and the final result. We cover webhooks in a later module.

Advertisement

Stateless: Why Every Request Must Carry Everything

REST APIs are stateless: the server does not remember your previous request. That is why your token goes in every request header. For testers this means:

  • Each test can be run alone, in any order, which makes parallel automation easy.
  • If a test passes only after another test ran first, it has a hidden dependency. Create your own test data inside each test instead.

Common Mistakes Beginners Make

  • Checking only the status code and not the body. A 200 with the wrong total is still a bug.
  • Forgetting Content-Type: application/json when sending a JSON body by hand (cURL). The practice API answers 415 Unsupported Media Type.
  • Mixing up the base URL and the endpoint path, or adding double slashes.
  • Not verifying that a create or update was really saved with a follow-up GET.
  • Hardcoding ids that another tester or test run may delete.
Advertisement

Interview Questions: How APIs Work

Explain the request-response cycle of an API.

The client sends an HTTP request containing a method, URL, headers and an optional body to an endpoint. The server authenticates it, runs business logic, reads or writes data and returns a response with a status code, headers and a body. Each cycle is independent because REST is stateless.

What is the difference between a base URL, a resource and an endpoint?

The base URL is the common root such as https://sqatools.in/wp-json/sqa-api/v1. A resource is the noun being managed, such as /users. An endpoint is a method plus a full path, such as GET /users/1.

What are the main parts of an HTTP request?

Method, URL (including path and query parameters), headers and an optional body. The protocol version is also part of the request line.

What are the main parts of an HTTP response?

A status line with the status code, response headers and an optional body. Some responses such as 204 No Content and 304 Not Modified have no body.

What does stateless mean in REST?

The server keeps no client session between requests. Every request must contain all information needed to process it, including authentication. This makes APIs scalable and makes tests independent.

What is the role of an API gateway?

An API gateway is the single entry point in front of many services. It handles authentication, rate limiting, routing, logging and sometimes caching. Testers often see 401, 429 or 502 errors coming from the gateway rather than from the service.

What is the difference between synchronous and asynchronous APIs?

A synchronous API returns the final result in the same response. An asynchronous API accepts the work (often 202 Accepted), returns a job id, and the client polls or receives a webhook when the job finishes.

Why does a POST that creates a resource usually return a Location header?

The Location header gives the URL of the new resource, so the client can fetch it without building the URL. Testers should assert it exists, points to the new id and returns the same data on GET.

How do you verify that a POST actually saved data?

Check the 201 status and returned body, then call GET on the new resource (or list endpoint) and compare the stored values. Optionally verify in the database if you have access.

What is API documentation and which format is common?

API documentation lists endpoints, parameters, request and response examples, error codes and authentication. The most common format is the OpenAPI Specification, often displayed with Swagger UI.

Advertisement
View the full API testing syllabus

What Is API Testing? A Beginner’s Guide with Real-Life Examples

What Is API Testing? A Beginner’s Guide with Real-Life Examples

Every time you pay with UPI, track a Swiggy order or check the weather on your phone, dozens of APIs talk to each other behind the screen. If one of them sends wrong data, the app breaks, even when the screen looks perfect. In this lesson you will learn what API testing is, why companies depend on it, what exactly a tester checks, and you will send your first real API request on a free practice API.

Quick answerAPI testing is a type of software testing where you send requests directly to an application’s API (Application Programming Interface) and check the response: the status code, the data in the body, the headers, the response time and the error handling. It tests the business logic without the user interface, so it is faster, more stable and finds bugs earlier than UI testing.
Advertisement

What is an API? (The Restaurant Waiter Example)

API stands for Application Programming Interface. It is a contract that lets one piece of software ask another piece of software for data or for an action, using a fixed set of rules.

Real-life example: the restaurant waiter You (the client) sit at a table. The kitchen (the server) cooks the food. You never walk into the kitchen. Instead, the waiter (the API) takes your order in a fixed format (“one paneer tikka, less spicy”), carries it to the kitchen and brings back the dish, or comes back with “sorry, paneer is finished”. The menu is the API documentation: it tells you what you can order and how.

Map that to software:

RestaurantSoftware worldExample
CustomerClient (mobile app, browser, another service)Swiggy app on your phone
WaiterAPIPOST /orders
KitchenServer, database, business logicOrder service + restaurant system
MenuAPI documentation (Swagger / OpenAPI)List of endpoints and fields
Your order slipRequest (method, URL, headers, body)JSON with item ids and address
The dish or “item finished”Response (status code + body)201 Created or 409 Conflict

What Is API Testing?

API testing means acting like the client: you send requests to the API and verify that every response is correct. You are not clicking buttons. You are checking the layer that every button eventually calls.

When you test an API you ask questions like:

  • Does GET /users/1 return 200 OK and the right user?
  • Does GET /users/999 return 404 Not Found with a clear error message, not a 500 crash?
  • Does creating an order with a negative quantity get rejected?
  • Can a user without permission delete someone else’s data?
  • Does the API answer in under 500 ms when 1,000 users call it together?
Where API testing sits In the test automation pyramid, unit tests are at the bottom, UI tests at the top, and API (service or integration) tests in the middle. Most teams want many API tests because they cover real business rules but run in milliseconds and rarely break when the UI design changes.
Advertisement

Why API Testing Is So Important

Modern applications are built as many small services talking over APIs. A single Flipkart checkout can call the cart service, pricing service, coupon service, payment gateway, inventory and delivery partner APIs. The UI is just a thin layer on top.

FactorUI testingAPI testing
SpeedSeconds per test (browser must load)Milliseconds per test
StabilityBreaks when locators or layout changeStable as long as the contract stays the same
When you can startOnly after the UI is builtAs soon as the endpoint exists (even before UI)
CoverageLimited to what the screen allowsEvery field, every error, every role
Bug location“Something is wrong on the checkout page”“POST /orders returns total 0 when coupon is 100%”
Cost of maintenanceHighLow

Because of this, API testing is one of the most requested skills in QA job descriptions in 2026, for both manual testers and automation engineers.

Real-Life Example: Testing a Food Delivery Order API

Imagine you are the tester for a food delivery app. The developer tells you the new endpoint POST /orders is ready, but the UI will take another two weeks. With API testing you do not wait. You test it today.

  1. Happy path: send a valid order with 2 items. Expect 201 Created, an order id, the correct total and status "placed".
  2. Calculation check: 2 x Rs 799 + 1 x Rs 349 = Rs 1,947. Add 18% tax and the total must be Rs 2,297.46. (This exact order exists on the practice API as GET /orders/5001.)
  3. Negative tests: quantity 0, unknown item id, missing address. Each should return 400 or 422 with a clear message.
  4. Security: call without a login token (expect 401), call with another customer’s token for this order (expect 403 or 404).
  5. Performance: response time under the agreed SLA, for example 800 ms.

By the time the UI arrives, the business logic is already proven. UI testers only need to check that the screen shows what the API returns.

Advertisement

What Do You Check in API Testing?

What to verifyExample checkWhy it matters
Status code201 after create, 404 for missing idClients decide what to do based on it
Response body valuesname is “Asha Verma”, total is 2297.46Wrong data = wrong screen or wrong bill
Schema / structureEvery user has id (integer), email (string)Missing fields crash mobile apps
HeadersContent-Type: application/json, LocationCaching, security and parsing depend on them
Error handlingBad input gives 422 with field errors, not 500Users must see helpful messages
Authentication and authorizationNo token = 401, wrong role = 403Prevents data leaks
PerformanceResponse under 500 ms; rate limit gives 429Slow APIs make slow apps
Data persistenceAfter POST, a GET returns the same dataProves the database really changed

You will learn each of these in detail in the next lessons, especially HTTP status codes and HTTP headers.

Advertisement

Your First API Test in 3 Ways

SQA Tools gives you a free practice REST API with no sign-up. Its base URL is https://sqatools.in/wp-json/sqa-api/v1. Let’s fetch user number 1.

1. In the browser (press Send request)

GEThttps://sqatools.in/wp-json/sqa-api/v1/users/1
curl -i \
  "https://sqatools.in/wp-json/sqa-api/v1/users/1"

You should see 200 OK and a JSON body with "name": "Asha Verma", "role": "admin" and "city": "Pune". This data is hardcoded, so the response is always the same, which makes it perfect for practising assertions.

2. In Postman (manual testing)

  1. Open Postman and click New → HTTP Request.
  2. Keep the method as GET and paste https://sqatools.in/wp-json/sqa-api/v1/users/1.
  3. Click Send. Check the status (200), time (ms) and body.
  4. Now change the id to 999 and send again. You get 404 with the message “User 999 does not exist. Valid ids are 1 to 12.” That is your first negative test.

3. With Playwright and TypeScript (automation)

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

const BASE = 'https://sqatools.in/wp-json/sqa-api/v1';

test('GET /users/1 returns Asha Verma', async ({ request }) => {
  const response = await request.get(`${BASE}/users/1`);

  expect(response.status()).toBe(200);
  expect(response.headers()['content-type']).toContain('application/json');

  const body = await response.json();
  expect(body.data).toMatchObject({ id: 1, name: 'Asha Verma', role: 'admin', city: 'Pune' });
});

test('GET /users/999 returns 404 with a clear message', async ({ request }) => {
  const response = await request.get(`${BASE}/users/999`);

  expect(response.status()).toBe(404);
  const body = await response.json();
  expect(body.error.code).toBe('not_found');
});

Run it with npx playwright test. No browser opens: Playwright’s request fixture sends pure HTTP calls. You will build full frameworks with this later in the course, and you can already read Playwright API testing basics.

Advertisement

Manual vs Automated API Testing

Manual API testingAutomated API testing
ToolsPostman, SoapUI, cURL, Swagger UIPlaywright, REST Assured, pytest + requests, Newman
Best forExploring a new endpoint, quick checks, bug reproductionRegression, CI/CD pipelines, data-driven and load tests
Skill neededHTTP basics, JSON, test designAll of that plus a programming language
Speed at scaleSlow for 500 test cases500 tests in under a minute

Real teams use both. A tester explores the new endpoint manually in Postman, writes the test cases, then automates the stable ones so they run on every code change.

  • Postman: the most popular GUI tool for manual and scripted REST testing; Newman runs collections in CI.
  • SoapUI / ReadyAPI: strong for SOAP web services (WSDL) and also supports REST.
  • Playwright (TypeScript): one framework for both UI and API automation; fast, parallel and great reports.
  • REST Assured: Java library popular in Selenium + Java teams.
  • cURL: command-line tool available everywhere; developers often share bugs as cURL commands.
  • JMeter and k6: load and performance testing of APIs.
  • Swagger UI: interactive documentation where you can try endpoints in the browser.
Advertisement

Common Bugs Found by API Testing

  • Wrong status codes, such as 200 OK with an error message inside the body, or 500 for simple invalid input.
  • Missing validation: negative prices, ages of 500, emails without “@” accepted.
  • Calculation errors in totals, tax, discounts or currency rounding.
  • Broken authorization: user A can read or change user B’s orders by changing the id in the URL (called BOLA/IDOR, the number one API security risk).
  • Sensitive data leaks, such as password hashes or internal ids in the response.
  • Pagination bugs: the last page repeats records or skips one.
  • Slow responses or no rate limiting.
  • Contract breaks: a field renamed from user_name to username without telling the mobile team.

How to Start Learning API Testing (Roadmap)

  1. Understand how an API works: request, response, endpoint.
  2. Learn HTTP methods and status codes.
  3. Learn JSON and headers.
  4. Practise manually with Postman and cURL on the SQA Tools practice API (141 ready scenarios).
  5. Learn authentication: Basic, API key, Bearer JWT.
  6. Automate with Playwright and TypeScript, then build the 5 projects in this course.
  7. Use AI to generate test cases and code faster, and prepare with the interview questions.
Advertisement

API Testing Interview Questions

What is API testing?

API testing is a type of software testing that validates an application’s APIs directly by sending requests and verifying responses: status code, body data, schema, headers, performance, security and error handling, without using the user interface.

Why is API testing preferred over UI testing?

API tests are faster, more stable, can start before the UI is ready, cover more combinations of data and roles, and point to the exact failing service. UI tests are still needed to check the user experience, but most business logic should be covered at the API level.

What is the difference between an API and a web service?

Every web service is an API that works over a network (usually HTTP), but not every API is a web service. For example, a Java library or an operating system interface is an API but not a web service. SOAP and REST services are web services.

What do you verify in an API response?

The status code, response body values, JSON schema (field names and data types), headers such as Content-Type and Location, response time, error messages for invalid input, and that the change is actually saved by calling a GET afterwards.

Can you do API testing without the UI being ready?

Yes. That is one of the biggest benefits. Using the API documentation (Swagger/OpenAPI) you can test endpoints as soon as developers deploy them, which is a key part of shift-left testing.

Which tools have you used for API testing?

A good answer names one manual and one automation tool and how you used them, for example: “Postman for exploring and collections run with Newman in CI, and Playwright with TypeScript for automated regression of 300 API tests in GitHub Actions.”

What are common bugs found in API testing?

Wrong status codes, missing input validation, calculation errors, broken authorization (accessing another user’s data), sensitive data in responses, pagination errors, poor performance and unannounced contract changes.

What is the test pyramid and where do API tests fit?

The test pyramid recommends many fast unit tests at the base, a good number of API/service tests in the middle and a small number of UI end-to-end tests at the top. API tests give the best balance of speed and business coverage.

What is an endpoint?

An endpoint is a specific URL plus HTTP method where an API accepts requests, for example GET https://sqatools.in/wp-json/sqa-api/v1/users/1. The base URL is shared, and each endpoint represents one resource or action.

How would you test a login API?

Valid credentials return 200 and a token; wrong password and unknown user return 401 with the same generic message; missing fields return 400 or 422; the token works on a protected endpoint and expires as configured; repeated failures are rate limited; and the password never appears in responses or logs.

Advertisement
View the full API testing syllabus