the complete guide to apis: rest, graphql, and websockets
APIs (Application Programming Interfaces) are the invisible glue holding the modern web together. Every time you check the weather on your phone, send a tweet, or make an online payment, you're interacting with APIs. But not all APIs are created equal, and choosing the right architecture can make or break your application.
In this comprehensive guide, we'll explore the three dominant API paradigms: REST (the established standard), GraphQL (the flexible challenger), and WebSockets (the real-time specialist). You'll learn how each works, when to use them, and see practical code examples that you can implement today.
What is an API?
An API is a contract between two pieces of software, defining how they can communicate. Think of it as a menu at a restaurant: the menu tells you what dishes (data/functions) are available and how to order them (request format), but you don't need to know how the kitchen (server) prepares them.
In web development, APIs typically allow a client (like a mobile app or website) to request data from a server. The server processes the request and sends back a response, usually in JSON format.
A Simple API Example
Imagine you're building a weather app. Instead of collecting weather data yourself, you use a weather API:
GET https://api.weather.com/v1/current?city=London
Response:
{
"temperature": 15,
"conditions": "cloudy",
"humidity": 72
}
REST: The Established Standard
REST (Representational State Transfer) is an architectural style introduced by Roy Fielding in 2000. It's not a protocol or standard, but a set of constraints that, when followed, create scalable and maintainable web services.
Core Principles of REST
1. Client-Server Architecture
The client and server are separate entities that communicate over HTTP. This separation allows them to evolve independently.
2. Statelessness
Each request from client to server must contain all the information needed to understand and process the request. The server doesn't store client context between requests.
3. Cacheability
Responses must define themselves as cacheable or non-cacheable to prevent clients from reusing stale data.
4. Uniform Interface
Resources are identified by URLs, and standard HTTP methods (GET, POST, PUT, DELETE) are used to manipulate them.
5. Layered System
The client can't tell whether it's connected directly to the end server or an intermediary (like a load balancer or cache).
HTTP Methods in REST
RESTful APIs use standard HTTP methods to perform CRUD (Create, Read, Update, Delete) operations:
| Method | Purpose | Idempotent | Example |
|---|---|---|---|
| GET | Retrieve data | Yes | GET /users/123 |
| POST | Create new resource | No | POST /users |
| PUT | Update/replace resource | Yes | PUT /users/123 |
| PATCH | Partial update | No | PATCH /users/123 |
| DELETE | Remove resource | Yes | DELETE /users/123 |
REST API Example
Let's build a simple REST API for managing blog posts. Here's how different operations would look:
Creating a Blog Post (POST)
POST /api/posts
Content-Type: application/json
{
"title": "Understanding REST APIs",
"content": "REST is an architectural style...",
"author": "John Doe"
}
Response (201 Created):
{
"id": 42,
"title": "Understanding REST APIs",
"content": "REST is an architectural style...",
"author": "John Doe",
"createdAt": "2025-11-26T10:30:00Z"
}
Retrieving All Posts (GET)
GET /api/posts?page=1&limit=10
Response (200 OK):
{
"posts": [
{
"id": 42,
"title": "Understanding REST APIs",
"author": "John Doe"
},
{
"id": 43,
"title": "GraphQL vs REST",
"author": "Jane Smith"
}
],
"total": 156,
"page": 1
}
Updating a Post (PUT)
PUT /api/posts/42
Content-Type: application/json
{
"title": "Understanding REST APIs - Updated",
"content": "REST is an architectural style for distributed systems..."
}
Response (200 OK):
{
"id": 42,
"title": "Understanding REST APIs - Updated",
"content": "REST is an architectural style for distributed systems...",
"updatedAt": "2025-11-26T11:00:00Z"
}
Deleting a Post (DELETE)
DELETE /api/posts/42
Response (204 No Content)
REST Pros and Cons
Advantages
- Simple and intuitive
- Stateless (easy to scale)
- Cacheable responses
- Wide tooling support
- Works with standard HTTP
- Well-documented patterns
Disadvantages
- Over-fetching (getting too much data)
- Under-fetching (multiple requests needed)
- Versioning challenges
- No built-in real-time support
- Can be chatty (many round trips)
GraphQL: The Flexible Alternative
GraphQL, developed by Facebook in 2012 and open-sourced in 2015, is a query language for APIs. Unlike REST, where the server defines what data is returned, GraphQL lets the client specify exactly what it needs.
How GraphQL Works
In GraphQL, you have a single endpoint (typically /graphql) that accepts
queries. The client sends a query describing the data structure it wants, and the server responds with
exactly that data—nothing more, nothing less.
GraphQL Query Example
Instead of multiple REST endpoints, you write a query:
query {
user(id: "123") {
name
email
posts {
title
createdAt
comments {
author
text
}
}
}
}
Response:
{
"data": {
"user": {
"name": "John Doe",
"email": "john@example.com",
"posts": [
{
"title": "My First Post",
"createdAt": "2025-11-20T10:00:00Z",
"comments": [
{
"author": "Jane",
"text": "Great post!"
}
]
}
]
}
}
}
Notice how the response structure exactly matches the query structure. This eliminates over-fetching and under-fetching.
GraphQL Mutations
While queries fetch data, mutations modify data. Here's how you'd create a blog post in GraphQL:
mutation {
createPost(
title: "Understanding GraphQL",
content: "GraphQL is a query language...",
authorId: "123"
) {
id
title
createdAt
author {
name
}
}
}
Response:
{
"data": {
"createPost": {
"id": "456",
"title": "Understanding GraphQL",
"createdAt": "2025-11-26T10:30:00Z",
"author": {
"name": "John Doe"
}
}
}
}
GraphQL Schema
GraphQL APIs are strongly typed. You define a schema that describes all available types and operations:
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
comments: [Comment!]!
createdAt: DateTime!
}
type Comment {
id: ID!
text: String!
author: String!
}
type Query {
user(id: ID!): User
posts(limit: Int, offset: Int): [Post!]!
}
type Mutation {
createPost(title: String!, content: String!, authorId: ID!): Post!
updatePost(id: ID!, title: String, content: String): Post!
deletePost(id: ID!): Boolean!
}
GraphQL Pros and Cons
Advantages
- No over-fetching or under-fetching
- Single endpoint
- Strongly typed schema
- Excellent developer tools
- Built-in documentation
- Flexible queries
Disadvantages
- Steeper learning curve
- Caching is more complex
- Can be overkill for simple APIs
- Query complexity can impact performance
- File uploads are non-standard
WebSockets: Real-Time Communication
Both REST and GraphQL follow a request-response model: the client asks, the server answers. But what if you need real-time, bidirectional communication? That's where WebSockets come in.
WebSockets provide a persistent, full-duplex connection between client and server. Once established, both sides can send messages at any time without the overhead of HTTP headers on every message.
How WebSockets Work
The WebSocket Handshake
Client Initiates
Client sends an HTTP request with an "Upgrade: websocket" header
Server Accepts
Server responds with "101 Switching Protocols" if it supports WebSockets
Connection Established
The HTTP connection is upgraded to a WebSocket connection
Bidirectional Communication
Both client and server can send messages at any time
WebSocket Code Example
Here's how you'd implement a simple WebSocket connection in JavaScript:
Client-Side (JavaScript)
// Create WebSocket connection
const socket = new WebSocket('wss://example.com/chat');
// Connection opened
socket.addEventListener('open', (event) => {
console.log('Connected to server');
socket.send(JSON.stringify({
type: 'join',
username: 'John'
}));
});
// Listen for messages
socket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
console.log('Message from server:', data);
if (data.type === 'chat') {
displayMessage(data.username, data.message);
}
});
// Send a message
function sendMessage(text) {
socket.send(JSON.stringify({
type: 'chat',
message: text
}));
}
// Connection closed
socket.addEventListener('close', (event) => {
console.log('Disconnected from server');
});
// Error handling
socket.addEventListener('error', (error) => {
console.error('WebSocket error:', error);
});
WebSocket Use Cases
Chat Applications
Real-time messaging where users need instant delivery of messages without polling.
Live Sports Scores
Push score updates to thousands of users simultaneously as events happen.
Collaborative Editing
Google Docs-style applications where multiple users edit the same document.
Financial Tickers
Stock prices and cryptocurrency values that update in real-time.
Gaming
Multiplayer games requiring low-latency, bidirectional communication.
IoT Dashboards
Real-time sensor data streaming from devices to monitoring dashboards.
WebSocket Pros and Cons
Advantages
- True real-time communication
- Bidirectional data flow
- Low latency
- Reduced overhead (no HTTP headers per message)
- Server can push updates
Disadvantages
- More complex to implement
- Stateful (harder to scale)
- No automatic reconnection
- Firewall/proxy compatibility issues
- Resource intensive (persistent connections)
Choosing the Right API Architecture
There's no one-size-fits-all answer. The best choice depends on your specific requirements:
| Scenario | Best Choice | Why |
|---|---|---|
| Simple CRUD app | REST | Simple, well-understood, easy to cache |
| Mobile app with limited bandwidth | GraphQL | Fetch only needed data, reduce payload size |
| Chat application | WebSockets | Real-time, bidirectional communication |
| Complex data relationships | GraphQL | Flexible queries, avoid multiple requests |
| Public API for third parties | REST | Familiar, widely supported, good documentation |
| Live dashboard with updates | WebSockets | Server can push updates without polling |
| Microservices communication | REST or gRPC | Stateless, scalable, language-agnostic |
Pro Tip: You Can Mix Them
Many modern applications use a combination. For example, you might use REST for most operations, GraphQL for complex data fetching on mobile apps, and WebSockets for real-time notifications. Choose the right tool for each job.
Tools to Help You Work with APIs
Working with APIs requires the right tools. Here are some from onlinetinker that can help:
JSON Formatter
Format and validate JSON responses from APIs.
Base64 Encoder
Encode data for API transmission and authentication.
Meta Tags Generator
Create Open Graph tags for API documentation pages.
Text Counter
Count characters in API payloads and responses.
Conclusion
APIs are the backbone of modern software development, enabling applications to communicate, share data, and build upon each other's capabilities. Understanding the differences between REST, GraphQL, and WebSockets empowers you to make informed architectural decisions.
REST remains the go-to choice for most applications due to its simplicity and wide support. GraphQL shines when you need flexible queries and want to minimize data transfer. WebSockets are essential for real-time, bidirectional communication.
The best developers don't dogmatically stick to one approach—they understand the strengths and weaknesses of each and choose the right tool for the job. As you build your next application, consider your specific requirements: Do you need real-time updates? Are you optimizing for mobile bandwidth? Is your data highly relational? Let these questions guide your choice.