You're building an integration. The third-party vendor hands you their API docs. It's either REST or SOAP, and if you picked wrong in your initial design, you're about to have a bad week.
Here's what actually matters when you're staring at that documentation.
The Real Difference That Matters
REST treats everything as a resource with a URL. You GET a user, POST a new order, DELETE a subscription. It's how the web works, using simple HTTP verbs to do predictable things.
SOAP wraps everything in XML envelopes like it's 2003. Every request is a POST. Every response is wrapped in three layers of XML. Your debugging sessions involve scrolling through angle brackets until you question your career choices.
But here's the thing: sometimes SOAP is the only option. Legacy enterprise systems, banking APIs, and government services often speak SOAP like Workday, Netsuite which are very popular amongst enterprise customers; you either learn their language or find another integration.
Quick Comparison (For Skimmers)
Aspect | REST | SOAP | GraphQL |
---|---|---|---|
Payload Size | ~1KB JSON | ~5KB XML | ~2KB JSON |
Auth Method | Bearer/OAuth | WS-Security | Bearer/API Keys |
HTTP Caching | Native support | None | Complex |
Learning Curve | 1 day | 1 week | 3 days |
Error Handling | HTTP status codes | SOAP faults in 200 OK | Field-level errors |
Best For | Web/Mobile apps | Enterprise/Banking | Complex data needs |
REST API Calls: What They Actually Look Like
Getting User Data (The Daily Bread)
GET https://api.example.com/users/123
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Accept: application/json
Response comes back clean:
{
"id": 123,
"name": "John Doe",
"email": "john@example.com",
"created_at": "2025-01-15T10:30:00Z"
}
No ceremony. No wrapper. Just data.
Creating Resources (When Things Go Right)
POST https://api.example.com/users
Content-Type: application/json
Authorization: Bearer token_here
{
"name": "Jane Smith",
"email": "jane@example.com",
"role": "developer"
}
You get back a 201 Created with the new resource. Status codes tell you what happened. 400? You messed up. 500? They messed up. 401? Your token expired three minutes ago.
Updating (The PATCH vs PUT Debate)
PUT https://api.example.com/users/123
Content-Type: application/json
{
"name": "John Updated",
"email": "john.updated@example.com"
}
PUT replaces the whole resource. PATCH updates just what you send. Most developers misuse PUT, and the difference often goes unnoticed until production data gets accidentally wiped.
SOAP API Calls: The XML Experience
Temperature Conversion (The Classic Example)
POST https://www.w3schools.com/xml/tempconvert.asmx
Content-Type: text/xml; charset=utf-8
SOAPAction: "https://www.w3schools.com/xml/CelsiusToFahrenheit"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<CelsiusToFahrenheit xmlns="https://www.w3schools.com/xml/">
<Celsius>25</Celsius>
</CelsiusToFahrenheit>
</soap:Body>
</soap:Envelope>
Twenty-five becomes seventy-seven, but only after parsing this response:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<CelsiusToFahrenheitResponse xmlns="https://www.w3schools.com/xml/">
<CelsiusToFahrenheitResult>77</CelsiusToFahrenheitResult>
</CelsiusToFahrenheitResponse>
</soap:Body>
</soap:Envelope>
That's 11 lines of XML to convert one number. This is why REST won.
Authentication (Where SOAP Gets Complex)
SOAP's WS-Security standard means your auth looks like this:
<soap:Header>
<security:Security xmlns:security="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<security:UsernameToken>
<security:Username>admin</security:Username>
<security:Password>password123</security:Password>
</security:UsernameToken>
</security:Security>
</soap:Header>
Meanwhile, REST just slaps a Bearer token in the header and calls it a day.
GraphQL: The Third Option You Might Need
POST https://api.example.com/graphql
Content-Type: application/json
{
"query": "{ user(id: 123) { name email posts { title } } }"
}
One endpoint. Ask for what you need. Get exactly that. No overfetching. No underfetching. Just frontend developers complaining about resolver performance and N+1 queries.
GraphQL shines when:
- Mobile apps need different data than web
- You're tired of versioning REST endpoints
- Frontend teams want independence
GraphQL hurts when:
- You just need simple CRUD operations
- Caching becomes a distributed systems problem
- Junior developers discover nested queries can DDoS your database
Technical Differences That Actually Impact Your Code
Data Format: REST speaks JSON (usually), XML (if you're unlucky), or plain text. SOAP primarily uses XML, though it supports binary attachments via MTOM/XOP for those 50MB PDFs your enterprise client insists on sending. When your JavaScript app needs to consume SOAP, you're parsing XML in the browser like it's 2005.
Error Handling: REST uses HTTP status codes. 404 means not found. Simple. SOAP returns 200 OK even when everything exploded, then makes you parse the XML to find the fault element buried inside. GraphQL? Also 200 OK with errors in the response body. Pattern emerging here.
Performance: REST payloads are smaller. A REST response might be 1KB of JSON. The same SOAP response is 5KB of XML. GraphQL sits in between - more than REST (includes schema), less than SOAP (no envelope overhead). Multiply by thousands of requests. Your bandwidth bill notices.
Security: SOAP has WS-Security baked in with standards for encryption, signatures, and SAML assertions. REST relies on HTTPS and OAuth. GraphQL inherits whatever you implement. SOAP's approach is bulletproof but requires a PhD to implement correctly.
Testing Tools That Actually Work
For Visual People
Postman: The default choice. Handles REST beautifully, struggles with SOAP. Environment variables save your sanity when switching between dev and prod. GraphQL support exists but feels bolted on.
SoapUI: Built for SOAP, tolerates REST. Imports WSDL files and generates all your requests. Ugly interface, powerful features. Ignores GraphQL's existence.
Insomnia: Cleaner than Postman, fewer features. Great for REST, pretends SOAP doesn't exist. Actually good GraphQL support with schema introspection.
Thunder Client: Lives in VS Code. Perfect when you're too lazy to alt-tab.
Bruno: Open source, stores collections as files. Git-friendly. Your team might actually use it.
For Terminal Warriors
curl for REST:
curl -X GET https://api.example.com/users \
-H "Authorization: Bearer token"
curl for SOAP (yes, it works):
curl -X POST -H "Content-Type: text/xml" \
-d @soap_request.xml https://api.example.com/soap
curl for GraphQL:
curl -X POST https://api.example.com/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ users { name } }"}'
HTTPie - curl for humans:
http GET api.example.com/users Authorization:"Bearer token"
Libraries That Actually Work
JavaScript/Node.js
For REST: axios or native fetch. Stop overthinking it.
const response = await axios.get('https://api.example.com/users');
// or
const response = await fetch('https://api.example.com/users');
For SOAP: Use strong-soap or soap-typescript in 2025. Callbacks are dead.
import { Client } from 'soap-typescript';
const client = await Client.createClient(wsdlUrl);
const result = await client.MyMethodAsync({param: value});
For GraphQL: Apollo Client if you hate yourself, simple fetch if you don't.
const response = await fetch('/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: '{ users { name } }' })
});
Python
REST: requests. Nothing else matters.
import requests
response = requests.get('https://api.example.com/users')
SOAP: zeep actually makes it tolerable.
from zeep import Client
client = Client('https://example.com/service.wsdl')
result = client.service.MyMethod(param='value')
GraphQL: gql or just requests with a string.
query = """{ users { name email } }"""
response = requests.post('/graphql', json={'query': query})
Java
REST: OkHttp for simplicity, Retrofit for type safety. SOAP: JAX-WS is built-in. Apache CXF if you hate yourself. GraphQL: graphql-java if you must.
When to Use What
Use REST when:
- Building modern web or mobile apps
- You control both ends
- Speed and simplicity matter
- Your team values their sanity
- HTTP caching can save your bacon
Use SOAP when:
- Integrating with enterprise systems
- The bank/government/Fortune 500 requires it
- You need bulletproof security standards
- ACID transactions across distributed systems
- The year is 2003 (or it feels like it)
Use GraphQL when:
- Multiple clients need different data shapes
- You're building a product platform
- Frontend team is sophisticated enough
- You enjoy debugging resolver performance
Use all three when:
- You're building an API gateway like Apideck
- You hate your DevOps team
- Job security through complexity
Performance Numbers That Matter
Real-world latency breakdown for a user fetch:
- REST: 50ms network + 10ms processing = 60ms
- SOAP: 50ms network + 40ms XML parsing = 90ms
- GraphQL: 50ms network + 20ms resolution = 70ms
Add 10ms for each additional resolver in GraphQL. Add 30ms for each SOAP envelope layer. REST stays flat until you need 15 endpoints for one screen.
The Reality Check
Most developers pick REST. It's simpler, faster, and the documentation makes sense. JSON beats XML. HTTP verbs beat envelope protocols.
But SOAP still runs half the enterprise world. Those banking APIs aren't switching to REST because you tweeted about it. Learn both, use what works, and stop arguing about it on Reddit.
GraphQL? It's great until your junior developer writes a query that joins 17 tables. Then it's a resume-generating event.
The best API is the one that ships your feature. Everything else is noise.
Final Thoughts for Developers
Test your error cases. Half your API calls will fail in production for reasons nobody predicted. That beautiful happy-path code you wrote? It's going to meet network timeouts, malformed responses, and 503 errors at 3 AM.
Version your APIs. Put /v1/ in your URLs. Future you will thank present you when breaking changes become inevitable.
Rate limit everything. That innocent webhook endpoint will get hammered by a misconfigured client sending 10,000 requests per second.
Monitor your p95 latencies, not your averages. Your users experience the worst case, not the mean.
Document your APIs like a developer who has to use them will hunt you down if you don't. Because they will be you, six months from now, wondering what the hell past-you was thinking.
And remember: Apideck's Unify API handles all this complexity so you don't have to. One REST API to rule them all - whether the underlying system is REST, SOAP, or GraphQL. Because life's too short to implement another SOAP client.
Ready to get started?
Scale your integration strategy and deliver the integrations your customers need in record time.