Decoding the 6 Architectures Driving Modern APIs

Vesper Lee
6 min readAug 2, 2023

--

In the world of web development, choosing the right architectural style for your API is one of the most critical design decisions. It has implications on everything from performance, scalability, flexibility to developer experience. In this article, we will explore the core principles, use cases and code samples of 6 popular API architectures — REST, gRPC, WebSockets, SOAP, GraphQL and Webhooks.

Get ready for a quick deep dive into understanding the strengths and weaknesses of each architectural approach. By the end, you will have a solid grasp of which style works best for common API scenarios. Let’s get started!

REST

Definition

REST (Representational State Transfer) is an architectural style for building networked applications. It relies on standard HTTP methods and status codes to expose resources and enable client-server communication.

Principles

  • Resources are exposed as endpoints with unique URIs that clients can retrieve and manipulate.
  • HTTP methods like GET, POST, PUT, DELETE are used to operate on resources.
  • Responses use standard HTTP status codes to indicate outcomes.
  • Stateless design where each request contains all necessary information.
  • Can leverage caching and layered system for performance.

Applications

  • Building web APIs that can be consumed by diverse clients.
  • Developing mobile apps that need to communicate with backend servers.
  • Designing microservices architectures with services exposing REST APIs.
  • CRUD applications like blogs, e-commerce sites that need to manage resources.
  • Public APIs that require a uniform interface for accessing data.

Code Sample

from flask import Flask
app = Flask(__name__)

@app.route('/api/users', methods=['GET'])
def get_users():
# Return list of users
pass

@app.post('/api/users')
def create_user():
# Create new user
pass

The above Flask application exposes /users endpoint for HTTP methods on user resources.

gRPC

Definition

gRPC is an open-source remote procedure call (RPC) framework developed by Google. It uses HTTP/2 protocol and Protocol Buffers for request serialization.

Principles

  • Service definition using .proto files to describe APIs.
  • Code generation from .proto to generate client/server stubs.
  • HTTP/2 as the transport protocol for performance and multiplexing.
  • Protocol buffers for efficient serialization of data.
  • Supports unary RPCs and streaming RPCs.
  • Bi-directional streaming allows asynchronous data flow.

Applications

  • Microservices architecture where gRPC connects different services.
  • Developing distributed systems that require efficient networking.
  • polyglot systems where gRPC enables cross-language calls.
  • Mobile apps where gRPC minimizes data usage and latency.
  • Real-time systems that require asynchronous streaming.

Code Sample

import grpc
import helloworld_pb2
import helloworld_pb2_grpc

channel = grpc.insecure_channel('localhost:50051')
stub = helloworld_pb2_grpc.GreeterStub(channel)

response = stub.SayHello(helloworld_pb2.HelloRequest(name='John'))
print(response.message)

The above code shows a simple gRPC client making RPC call to the server.

WebSockets

Definition

WebSocket is a protocol that provides full-duplex communication over a single TCP connection between a client and server. It upgrades from HTTP protocol to enable real-time bidirectional event-driven communication.

Principles

  • Initial HTTP-based handshake to upgrade connection to WebSocket.
  • Persistent connection between client and server after handshake.
  • Full-duplex communication allowing both parties to send data at any time.
  • Frame-based messaging with optimized data transfer.
  • Sub-protocols can be layered for application-specific protocols.

Applications

  • Real-time applications like chats, notifications and live updates.
  • Collaborative editing tools and whiteboard apps.
  • Real-time financial data and stock tickers.
  • Online multiplayer games and virtual worlds.
  • IoT devices and control systems requiring continuous streams.

Code Sample

import websocket

ws = websocket.WebSocket()
ws.connect("ws://server.com/socket")

ws.send("Hello")
print(ws.recv())

ws.close()

The above code demonstrates a WebSocket client sending a message and receiving response from the server.

SOAP

Definition

SOAP (Simple Object Access Protocol) is a protocol for exchange of information in distributed computing environments. It uses XML for message formatting and relies on application layer protocols like HTTP for message negotiation and transmission.

Principles

  • XML-based messaging format with SOAP envelope and body.
  • Transport protocols like HTTP for message transmission.
  • Support for RPC pattern with request-response message exchange.
  • Interface definition using WSDL for specifying SOAP services.
  • Built-in support for security through WS-Security.

Applications

  • Enterprise application integration between disparate systems.
  • Transaction processing applications that require ACID compliance.
  • Legacy systems and SOAP-based web services.
  • Applications requiring formal contract and compliance to standards.
  • Systems needing end-to-end security, transactions and guarantees.

Code Sample

from suds.client import Client

client = Client("http://server.com/wsdl")

response = client.service.helloWorld("John")
print(response)

The above code shows a SOAP client using the suds library to invoke a SOAP web service.

GraphQL

Definition

GraphQL is an open-source data query and manipulation language for APIs. It allows clients to specify exactly what data they need via queries instead of getting predefined fixed data structures.

Principles

  • Strongly typed schema using GraphQL SDL.
  • Clients construct queries to fetch required data.
  • Single endpoint for all client queries and mutations.
  • Backend resolves and returns only requested data.
  • Built-in query analysis, validation and error handling.
  • Optional real-time subscriptions and live queries.

Applications

  • Client applications needing flexible data fetching control.
  • Frontend and mobile apps where network efficiency is critical.
  • Frequently changing APIs where maintaining compatibility is challenging.
  • Situations where over and under fetching data is problematic.
  • Real-time apps and collaborative platforms.

Code Sample

import requests

query = """
query GetUser {
user(id: 1) {
name
email
}
}
"""

response = requests.post(
url='http://api.com/graphql',
json={'query': query}
)

print(response.json())

The above shows a GraphQL query to selectively fetch fields of a user.

Webhooks

Definition

Webhooks allow apps to notify other apps about events happening in the first app through HTTP callbacks. The second app can subscribe to events in the first app to be notified when they occur.

Principles

  • Event-driven — triggered by something happening in the source app.
  • Registration — destination app registers a URL as webhook endpoint.
  • HTTP request — source app makes request to callback URL on events.
  • Payload — request contains metadata about the event as payload.
  • Asynchronous — notifications sent asynchronously to destination.

Applications

  • Real-time notifications about activities like payments, signups etc.
  • Integration with third-party platforms and syncing data.
  • Automating workflows and pipelines between apps.
  • Logging and monitoring critical events for analysis.
  • Async processing of computationally intensive tasks.

Code Sample

import requests

def webhook(event):
print("Got event: ", event)

subscription = {
'url': 'https://dst.com/webhook',
'events': ['order_created']
}

requests.post('http://src.com/register', json=subscription)

The above code shows a destination app registering a webhook to receive notifications from the source app.

There you have it — a whirlwind tour of 6 different API architectural styles and their unique characteristics. While there is no one-size-fits-all solution, evaluating your specific use case requirements will help determine the most appropriate option.

Here are some parting thoughts:

  • Don’t prematurely optimize for performance without proven bottlenecks.
  • Leverage existing standards before reinventing the wheel.
  • Consider future maintainability alongside current features.
  • Keep developer experience a first-class concern.

What have your experiences been with different API architectures? Which style resonated most with your projects and why? Share your thoughts below!

--

--