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.
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.
REST vs SOAP vs GraphQL: Comparison Table
| Feature | REST | SOAP | GraphQL |
|---|---|---|---|
| What it is | Architectural style | Protocol (W3C standard) | Query language + runtime |
| Data format | JSON mostly (also XML, text) | XML only | JSON |
| Endpoints | Many (one per resource) | One per service, many operations | Usually one (/graphql) |
| HTTP methods | GET, POST, PUT, PATCH, DELETE | Mostly POST | Mostly POST (GET for queries possible) |
| Contract | OpenAPI / Swagger (optional) | WSDL + XSD (mandatory) | Schema (SDL), strongly typed |
| Error reporting | HTTP status codes + error body | SOAP Fault element (often HTTP 500) | errors array, often with HTTP 200 |
| Caching | Easy (HTTP caching, ETag) | Hard | Hard (single POST endpoint), needs client caching |
| Security | HTTPS + OAuth 2.0/JWT | WS-Security (signing, encryption) + HTTPS | HTTPS + OAuth/JWT, plus query depth limits |
| Payload size | Medium | Large (XML envelope) | Small (only requested fields) |
| Learning curve | Easy | Steeper | Medium |
| Typical users | Most web and mobile apps | Banks, insurance, telecom, government | GitHub, Shopify, Meta, data-rich dashboards |
| Testing tools | Postman, Playwright, REST Assured | SoapUI, ReadyAPI, Postman | Postman, 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:
https://sqatools.in/wp-json/sqa-api/v1/users/1curl -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.
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,faultstringanddetail.
<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>
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).
How Test Cases Differ for Each Style
| Test area | REST | SOAP | GraphQL |
|---|---|---|---|
| Positive | Each method on each resource | Each WSDL operation | Each query and mutation, different field selections |
| Validation | 400/422 with field errors | SOAP Fault, XSD validation | Errors array, type errors from schema |
| Contract | JSON Schema / OpenAPI diff | WSDL/XSD compliance | Schema diff, deprecated fields |
| Security | Auth, BOLA, rate limit | WS-Security, XML injection, XXE | Field-level auth, depth/complexity limits, introspection off |
| Performance | Per endpoint | Per operation, payload size | Expensive nested queries, N+1 problem |
| Assertions | JSON path on body | XPath / XQuery | JSON 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.
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.
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.
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.