Types of APIs: REST, SOAP, GraphQL and More
APIs come in various types such as REST (resource-based), SOAP (protocol-based), and GraphQL (query-based).
Types of Application Programming Interface
APIs come in many forms, each designed for different communication patterns, performance requirements, and use cases. Understanding the different types of APIs helps you choose the right architecture for each project, communicate more effectively with other developers, and evaluate trade-offs between simplicity, flexibility, and performance.
What Is an API
An API (Application Programming Interface) is a defined contract that allows two software systems to communicate with each other. It specifies what requests can be made, what format they must follow, and what responses to expect. APIs abstract away the internal implementation of a system, exposing only the functionality that external callers need while hiding everything else.
The term API is broad and applies to many different contexts. A library exposes an API to the code that uses it. An operating system exposes an API to applications. A web service exposes an API over HTTP to clients across the internet. In modern web development, the term most commonly refers to web APIs that transfer data between a client and a server over HTTP, but the underlying concept applies universally wherever one piece of software needs to use the functionality of another.
Overview of API Types
| API Type | Protocol | Data Format | Best For |
|---|---|---|---|
| REST | HTTP | JSON, XML | Public APIs, web and mobile applications, standard CRUD operations |
| GraphQL | HTTP | JSON | Complex data requirements, multiple clients needing different data shapes |
| gRPC | HTTP/2 | Protocol Buffers (binary) | High-performance internal microservice communication |
| SOAP | HTTP, SMTP | XML | Enterprise systems, financial and government services requiring strict contracts |
| WebSocket API | WebSocket | JSON, binary | Real-time bidirectional communication, live chat, gaming |
| Webhook | HTTP | JSON, XML | Event-driven notifications, third-party integrations, automation |
| SSE | HTTP | Text | One-way server-to-client streaming, live feeds, notifications |
REST APIs
REST (Representational State Transfer) is an architectural style for building web APIs that uses standard HTTP methods to perform operations on resources identified by URLs. It is the most widely adopted API style in use today, powering the public APIs of virtually every major web platform including Twitter, GitHub, Stripe, and Google.
REST is not a protocol or a standard. It is a set of constraints described by Roy Fielding in his doctoral dissertation in 2000. An API that follows these constraints is called RESTful. The key constraints are that communication is stateless, meaning each request contains everything the server needs to process it independently, resources are identified by URLs, and the standard HTTP methods express the operation being performed.
GET /api/users → Retrieve a list of all users
GET /api/users/42 → Retrieve a specific user by ID
POST /api/users → Create a new user
PUT /api/users/42 → Replace an existing user completely
PATCH /api/users/42 → Update specific fields of a user
DELETE /api/users/42 → Delete a user
Response (JSON):
{
"id": 42,
"name": "Alice",
"email": "alice@example.com",
"role": "admin"
}
| Feature | Detail |
|---|---|
| Advantages | Simple and intuitive, uses standard HTTP tooling, stateless and cacheable, widely understood by developers, easy to test with browser or curl |
| Disadvantages | Over-fetching returns more data than needed, under-fetching requires multiple requests, no strict schema enforcement by default |
| Versioning | Typically handled through URL path versioning such as /api/v1/ or through custom headers |
| Best Used When | Building public APIs, connecting web and mobile frontends to backends, standard CRUD data operations |
GraphQL APIs
GraphQL is a query language for APIs developed by Facebook and released publicly in 2015. Instead of the server defining fixed endpoints that return fixed data shapes, GraphQL exposes a single endpoint to which clients send queries specifying exactly which fields they need. The server returns precisely that data, nothing more and nothing less.
This approach eliminates the over-fetching and under-fetching problems common in REST. A mobile client that only needs a user's name and avatar does not have to receive the full user object. A dashboard that needs data from five different entity types can retrieve it all in a single request rather than making five separate API calls.
// Query: ask for exactly the fields you need
query {
user(id: 42) {
name
email
posts {
title
createdAt
}
}
}
// Response: exactly what was requested, nothing extra
{
"data": {
"user": {
"name": "Alice",
"email": "alice@example.com",
"posts": [
{ "title": "What is DNS", "createdAt": "2024-01-15" },
{ "title": "How HTTP Works", "createdAt": "2024-02-03" }
]
}
}
}
mutation {
createUser(input: { name: "Bob", email: "bob@example.com" }) {
id
name
email
}
}
| Feature | Detail |
|---|---|
| Advantages | Clients request exactly the data they need, reduces network round-trips, self-documenting through introspection, strongly typed schema |
| Disadvantages | More complex to implement than REST, HTTP caching is harder because all requests go to one endpoint, can expose too much data if not carefully secured, steeper learning curve |
| Single Endpoint | All queries and mutations go through one URL, typically /graphql |
| Best Used When | Multiple clients (web, mobile, third party) need different data shapes, complex nested data relationships, rapid frontend iteration without backend changes |
gRPC APIs
gRPC (Google Remote Procedure Call) is a high-performance API framework developed by Google that allows code in one service to directly call functions in another service as if they were local function calls. It uses HTTP/2 as its transport and Protocol Buffers as its data serialisation format, producing a binary payload that is significantly smaller and faster to parse than JSON or XML.
Unlike REST and GraphQL, where you think in terms of resources and queries, gRPC is procedural: you define service methods that can be called remotely. A service definition written in a .proto file describes the available methods and the structure of their request and response messages. This file is used to auto-generate client and server code in any supported language, ensuring both sides always agree on the interface.
syntax = "proto3";
service UserService {
rpc GetUser (GetUserRequest) returns (User);
rpc CreateUser (CreateUserRequest) returns (User);
rpc ListUsers (ListUsersRequest) returns (stream User);
}
message GetUserRequest {
int32 id = 1;
}
message User {
int32 id = 1;
string name = 2;
string email = 3;
}
message CreateUserRequest {
string name = 1;
string email = 2;
}
message ListUsersRequest {
int32 page = 1;
int32 per_page = 2;
}
| Feature | Detail |
|---|---|
| Advantages | Very fast binary serialisation, strongly typed contracts, auto-generated client code in multiple languages, native streaming support, efficient multiplexing over HTTP/2 |
| Disadvantages | Binary format is not human-readable, requires tooling to inspect, browser support is limited without a proxy layer, steeper setup complexity than REST |
| Streaming | Supports server streaming, client streaming, and bidirectional streaming natively, unlike REST which requires workarounds |
| Best Used When | Internal microservice communication where performance matters, polyglot environments needing consistent cross-language interfaces, systems with large data volumes |
SOAP APIs
SOAP (Simple Object Access Protocol) is a protocol for exchanging structured information in web services. It was the dominant web API standard throughout the 2000s before REST displaced it for most new development. SOAP uses XML exclusively for both requests and responses and relies on a formal contract called a WSDL (Web Services Description Language) file that describes every operation the service provides.
SOAP is verbose and complex compared to REST or GraphQL, but it provides strict formal guarantees that enterprise and regulated industries value. It has built-in specifications for security (WS-Security), reliable messaging, and atomic transactions. Banking, healthcare, and government systems that were built during the SOAP era still rely on it, and its guarantees make it appropriate for any integration where contractual precision and auditability are requirements.
<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<AuthToken>abc123</AuthToken>
</soap:Header>
<soap:Body>
<GetUser>
<UserId>42</UserId>
</GetUser>
</soap:Body>
</soap:Envelope>
| Feature | Detail |
|---|---|
| Advantages | Strict formal contracts via WSDL, built-in security and transaction standards, language and transport independent, excellent tooling in enterprise environments |
| Disadvantages | Very verbose XML payload, complex to implement and debug, poor fit for mobile and browser clients, largely replaced by REST for new development |
| Contract | Defined by a WSDL file that precisely specifies every operation, message format, and data type |
| Best Used When | Integrating with legacy enterprise systems, banking and financial APIs, government services, any context requiring formal contracts and built-in transaction support |
WebSocket APIs
A WebSocket API establishes a persistent bidirectional connection between client and server, allowing either side to send messages at any time without waiting for a request. Unlike HTTP where the client always initiates, WebSocket connections remain open and the server can push data to the client the moment it is available.
WebSocket APIs are the right choice when your application needs real-time data flowing in both directions. The connection is established with an HTTP upgrade handshake and then switches to the WebSocket protocol, which has minimal per-message overhead compared to making a new HTTP request for each update.
const ws = new WebSocket('wss://api.example.com/live');
ws.onopen = () => {
ws.send(JSON.stringify({ action: 'subscribe', channel: 'prices' }));
};
ws.onmessage = (event) => {
const update = JSON.parse(event.data);
console.log('Price update:', update);
};
ws.onclose = () => console.log('Connection closed');
| Feature | Detail |
|---|---|
| Advantages | Low latency real-time updates, server can push data without a client request, minimal per-message overhead after the initial handshake |
| Disadvantages | Stateful connections complicate horizontal scaling, no built-in request-response pattern, reconnection logic must be implemented manually |
| Connection | Single persistent connection per client, established once and held open for the session duration |
| Best Used When | Live chat applications, multiplayer gaming, real-time dashboards, collaborative editing, any use case requiring instant bidirectional data flow |
Webhooks
A webhook is a reverse API pattern where instead of your application polling a service for updates, the service calls your application when an event occurs. You register a URL endpoint on your server, and the external service sends an HTTP POST request to that URL with event data whenever something relevant happens.
Webhooks are event-driven rather than request-driven. They eliminate the need for continuous polling and deliver updates the moment they occur. Stripe uses webhooks to notify your server when a payment succeeds or fails. GitHub uses webhooks to trigger your CI pipeline when code is pushed. Twilio uses webhooks to deliver incoming SMS messages to your application.
app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
// Verify the webhook signature to confirm it came from Stripe
event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET);
} catch (err) {
return res.status(400).send(`Webhook signature verification failed: ${err.message}`);
}
// Handle the event
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object;
console.log('Payment succeeded:', paymentIntent.id);
// Fulfil the order, send confirmation email, etc.
break;
case 'payment_intent.payment_failed':
console.log('Payment failed');
break;
}
res.json({ received: true });
});
| Feature | Detail |
|---|---|
| Advantages | Event-driven with no polling overhead, immediate notification when events occur, simple to consume as a standard HTTP POST endpoint |
| Disadvantages | Your server must be publicly accessible to receive webhooks, failed deliveries require retry handling, order of delivery is not always guaranteed |
| Security | Always verify the webhook signature provided by the sender to confirm the request is genuine and not forged by a third party |
| Best Used When | Reacting to events in third-party services, triggering workflows on payment, deployment, form submission, or message receipt events |
Server-Sent Events (SSE)
Server-Sent Events is a standard that allows a server to push a continuous stream of updates to a browser client over a single long-lived HTTP connection. Unlike WebSockets, SSE is unidirectional: data flows from server to client only. The client cannot send messages back over the SSE connection, though it can make separate HTTP requests alongside it.
SSE is simpler to implement than WebSockets for one-way streaming use cases. It uses standard HTTP, reconnects automatically if the connection drops, supports named event types, and works through HTTP/2 multiplexing. It is a good fit for live news feeds, real-time notifications, progress updates for long-running tasks, and any scenario where the server needs to push updates but the client does not need to send data back in real time.
// Server: send a stream of events
app.get('/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
const sendUpdate = () => {
res.write(`event: price-update\n`);
res.write(`data: ${JSON.stringify({ price: Math.random() * 100 })}\n\n`);
};
const interval = setInterval(sendUpdate, 1000);
req.on('close', () => clearInterval(interval));
});
// Client: listen for server-sent events
const evtSource = new EventSource('/events');
evtSource.addEventListener('price-update', (event) => {
const data = JSON.parse(event.data);
console.log('New price:', data.price);
});
evtSource.onerror = () => console.log('Connection error, will retry automatically');
| Feature | Detail |
|---|---|
| Advantages | Simple to implement over standard HTTP, automatic reconnection built into the browser, works with HTTP/2 multiplexing, no special server infrastructure required |
| Disadvantages | Unidirectional only. The client cannot send data back over the SSE stream. Browsers limit the number of concurrent SSE connections per domain. |
| Reconnection | The browser reconnects automatically after a dropped connection, using the last event ID to resume from where it left off if the server supports it |
| Best Used When | Live feeds, real-time notifications, streaming logs or build output, progress updates, any one-way server-to-client data flow |
Choosing the Right API Type
No single API type is best for every situation. The right choice depends on your performance requirements, the complexity of your data, whether communication needs to be bidirectional, and who will be consuming the API.
| Situation | Recommended Type | Reason |
|---|---|---|
| Public API for third-party developers | REST | Universally understood, easy to explore, well-supported by tooling and documentation generators |
| Multiple clients needing different data shapes | GraphQL | Each client queries only what it needs, eliminating over-fetching and multiple round-trips |
| High-performance internal microservices | gRPC | Binary serialisation, strongly typed contracts, and HTTP/2 streaming minimise latency and bandwidth |
| Legacy enterprise system integration | SOAP | Existing systems expose SOAP interfaces and require formal contracts |
| Real-time bidirectional features | WebSocket | Persistent connection with full duplex messaging for live chat, gaming, and collaboration |
| Reacting to external platform events | Webhook | Receive push notifications from payment providers, version control, and other platforms |
| One-way server-to-client live updates | SSE | Simpler than WebSockets for read-only streams, automatic reconnection, standard HTTP |
REST vs GraphQL vs gRPC: Direct Comparison
| Feature | REST | GraphQL | gRPC |
|---|---|---|---|
| Protocol | HTTP/1.1 or HTTP/2 | HTTP/1.1 or HTTP/2 | HTTP/2 only |
| Data Format | JSON (typically) | JSON | Protocol Buffers (binary) |
| Schema | Optional (OpenAPI) | Required (SDL) | Required (.proto file) |
| Fetching Flexibility | Fixed response shape per endpoint | Client specifies exact fields needed | Fixed response shape per method |
| Streaming | Not native (use SSE or polling) | Subscriptions via WebSocket | Native streaming in all directions |
| Browser Support | Full | Full | Requires proxy layer |
| Learning Curve | Low | Medium | High |
| Caching | Native HTTP caching | Custom caching required | Custom caching required |
Frequently Asked Questions
- What is the difference between REST and SOAP?
REST is an architectural style that uses standard HTTP methods and typically returns JSON. It is lightweight, flexible, and human-readable. SOAP is a strict protocol that uses XML for all messages and requires a formal WSDL contract describing the service. REST is the standard for most modern web and mobile APIs because of its simplicity and tooling support. SOAP remains in use for enterprise integrations, banking systems, and legacy services that were built when SOAP was the dominant standard and that rely on its formal security and transaction specifications. - When should I use GraphQL instead of REST?
GraphQL is most valuable when you have multiple clients with significantly different data needs, such as a web app, a mobile app, and a third-party integration all consuming the same API but requiring different fields. It eliminates the need to build separate endpoints or accept over-fetching for each client. REST is usually simpler and sufficient when your data model is straightforward, when you are building a public API that many different developers will consume, or when HTTP caching is important for your performance strategy, as GraphQL's single endpoint makes standard HTTP caching difficult. - What is the difference between a WebSocket API and SSE?
Both allow the server to push data to the client without the client polling, but they differ in direction and complexity. WebSockets are fully bidirectional: both the client and server can send messages at any time over the same connection. SSE is unidirectional: only the server can push data to the client. SSE is simpler to implement, reconnects automatically, and works over standard HTTP without a protocol upgrade. Choose WebSockets when the client needs to send data back in real time, such as in a chat application or multiplayer game. Choose SSE when only the server needs to send updates, such as a live notification feed or a streaming log viewer. - What is a webhook and how is it different from an API?
A traditional API is a pull model: your application makes a request to a service and receives a response. A webhook is a push model: the service sends a request to your application when an event occurs. Instead of your code calling Stripe's API every minute to check for new payments, Stripe calls your webhook endpoint immediately when a payment is made. Webhooks are more efficient for event-driven workflows because they eliminate polling. They require your server to have a publicly accessible endpoint that the external service can reach, and you should always verify the signature on incoming webhook requests to confirm they are genuine. - Can I use multiple API types in the same application?
Yes, and in practice most production applications do. A common pattern is to use REST for standard data retrieval and mutation operations, WebSockets or SSE for real-time features like notifications and live updates, webhooks to receive events from payment processors and third-party integrations, and gRPC for internal communication between backend microservices where performance is critical. Each API type is suited to different communication patterns, and using the right one for each part of your system produces a more efficient and maintainable architecture than forcing everything through a single approach.
Conclusion
The choice of API type shapes how data flows through your system, how your clients and servers communicate, and how much flexibility or performance you can achieve. REST remains the default for most public-facing web APIs because of its simplicity, wide tooling support, and universal familiarity. GraphQL solves the data fetching inefficiencies of REST when multiple clients have divergent needs. gRPC delivers maximum performance for internal microservice communication. SOAP serves enterprise and regulated industry integrations. WebSockets and SSE enable real-time data flows that HTTP alone cannot support. Webhooks complete the picture by allowing external services to notify your application the moment relevant events occur. Understanding the strengths and trade-offs of each type gives you the foundation to design APIs that are fast, maintainable, and appropriate for their context. Continue with REST APIs, HTTP methods, WebSockets, and HTTPS to deepen your understanding of web API communication.
