SOAP:
A messaging mechanism called SOAP (Simple Object Access mechanism) enables software applications running on various operating systems to communicate with one another over the Internet.
Web services are defined and their methods of access are described using the XML-based language known as WSDL (Web Services Description Language). It resembles an API specification for online services that use SOAP.
An XML document known as a SOAP message is made up of a root Envelope element, which may also contain a Header and a Body. The Header, which is optional, contains data pertinent to the SOAP message, frequently relating to transaction management, payment, and authentication. The Body, which is required, contains the XML information that makes up the message being sent.
The following example is a simple web service written in Java, using JAX-WS (Java API for XML Web Services):
@WebService
public class TaskService {
private Map<Integer, Task> tasks = new HashMap<>();
@WebMethod
public Task getTask(@WebParam(name = "taskId") int id) {
return tasks.get(id);
}
}
This creates a web service that uses SOAP to communicate. The getTask
method can be called remotely, and JAX-WS automatically takes care of creating the appropriate SOAP messages.
RESTful:
REST (Representational State Transfer) is a style of software architecture for distributed systems. A RESTful web service uses HTTP and the principles of REST to provide its services.
The same TaskService could look like this in a RESTful style, using Spring Boot in Java:
@RestController
@RequestMapping("/tasks")
public class TaskController {
private Map<Integer, Task> tasks = new HashMap<>();
@GetMapping("/{id}")
public Task getTask(@PathVariable("id") int id) {
return tasks.get(id);
}
}
The getTask
method can be accessed with a HTTP GET request to /tasks/{id}
. Spring Boot automatically handles incoming HTTP requests and routes them to the appropriate methods.
GraphQL:
GraphQL is a data query and manipulation language developed by Facebook. It provides a more efficient, powerful, and flexible alternative to REST. It allows clients to define the structure of the responses.
For GraphQL, we would need to define a schema for our service. This schema defines a Task
type and a query to get a task. We’re using JavaScript with express-graphql:
const { graphql, buildSchema } = require('graphql');
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
// Construct a schema
var schema = buildSchema(`
type Task {
id: Int,
title: String,
description: String,
status: String
}
type Query {
task(id: Int): Task
}
`);
// The root provides the resolver functions for each type of query
var root = {
task: ({id}) => {
return getTask(id);
},
};
// A simple function to fetch tasks
function getTask(id) {
// Logic to fetch the task
// return task;
}
var app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
}));
app.listen(4000);
Clients can now make a POST request to /graphql
with a body containing a GraphQL query that specifies exactly what data is needed.
gRPC:
gRPC is a high performance, open-source universal RPC (Remote Procedure Call) framework. It’s based on the HTTP/2 protocol and uses Protobuf (short for Protocol Buffers) by default as its interface definition language (IDL) to define the service interface and the structure of the payload messages.
Here’s the protobuf definition for our service:
// task.proto
syntax = "proto3";
package task;
service TaskService {
rpc GetTask (GetTaskRequest) returns (Task) {}
}
message GetTaskRequest {
int32 id = 1;
}
message Task {
int32 id = 1;
string title = 2;
string description = 3;
string status = 4;
}
The above defines the TaskService
with the GetTask
RPC method. GetTaskRequest
and Task
are the request and response types respectively.
Once we have the service defined, we can implement it in the server. Here’s how it might look in Python, using the grpc
library:
from concurrent import futures
import grpc
import task_pb2
import task_pb2_grpc
class TaskServiceServicer(task_pb2_grpc.TaskServiceServicer):
def GetTask(self, request, context):
task = get_task(request.id) # Function to fetch a task by ID
return task
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
task_pb2_grpc.add_TaskServiceServicer_to_server(TaskServiceServicer(), server)
server.add_insecure_port('[::]:50051')
server.start()
server.wait_for_termination()
if __name__ == '__main__':
serve()
WebSocket:
WebSocket provides a full-duplex communication channel over a single TCP connection. It’s commonly used for real-time applications. Here’s how you might handle the same task in Node.js using the ws
library:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', ws => {
ws.on('message', message => {
const request = JSON.parse(message);
if (request.type === 'getTask') {
const task = getTask(request.data.id); // Function to fetch a task by ID
ws.send(JSON.stringify(task));
}
});
});
The WebSocket server listens for incoming WebSocket connections. When a client sends a message of type ‘getTask’, it fetches the requested task and sends it back to the client.
Webhook:
An app can share real-time data with other applications using webhooks. You receive data promptly because webhooks provide data to other applications as it happens.
Webhooks don’t involve direct client interaction like the other examples do. Instead, anytime the pertinent data changes, the client would register a URL with the server, and the server would then issue an HTTP request to that URL.
We might wish to alert other services whenever a task’s status changes in our task manager application. For each job, we might keep a list of webhook URLs that we could use to implement this by making a POST request to each of them if the task’s state changes.
const axios = require('axios');
let task = {
id: 123,
title: 'My Task',
description: 'Do something',
status: 'Incomplete',
webhooks: ['http://example.com/webhook', 'http://another-example.com/webhook']
};
function updateTaskStatus(id, newStatus) {
task.status = newStatus;
task.webhooks.forEach(url => {
axios.post(url, {
taskId: task.id,
newStatus: task.status
});
});
}
In this example, the updateTaskStatus
function changes the status of a task and sends a POST request to each registered webhook URL with the new task status. This way, all the services that registered as webhooks for this task are immediately notified of the status change.
SOAP:
SOAP (Simple Object Access Protocol) is a protocol for exchanging structured information in web services using XML. It’s a heavyweight protocol that needs a lot of XML markup, which can be complex and verbose. SOAP uses a WSDL file (Web Services Description Language) that provides a machine-readable description of how the service can be called, what parameters it expects, and what data structures it returns. Philosophy: SOAP is designed to handle distributed computing environments which are not necessarily tied to HTTP protocol. It emphasizes flexibility and reliability, supporting communication between applications over networks, even when not using similar platforms, languages, or operating systems.
REST:
REST (Representational State Transfer) uses standard HTTP methods like GET, POST, PUT, DELETE for communication. It is lightweight compared to SOAP and doesn’t require a lot of XML markup. Since REST is stateless, each HTTP request should include all the data required to fulfill it. REST is predicated on the idea that objects (such as people, items, etc.) are resources that may be created, read, updated, and destroyed. It makes the most of the HTTP protocol to make using web services easier and more comprehensible.
GraphQL:
GraphQL is a query language for APIs. It allows the client to specify exactly what data it needs, making it possible to aggregate responses from multiple sources. It can potentially save bandwidth and make client side data management easier. Philosophy: GraphQL provides clients the power to ask for exactly what they need and nothing more. It provides a complete understanding of the data and gives clients the ability to ask for many resources in a single request.
gRPC:
gRPC (Google Remote Procedure Call) is a high-performance, open-source framework that can run in any environment. It allows for bi-directional streaming and has pluggable support for load balancing, tracing, health checking, and authentication. It uses Protocol Buffers (protobuf) as its interface definition language. Philosophy: gRPC is built for high-performance communication, particularly around microservices. It leverages HTTP/2 capabilities and introduces concepts like connection multiplexing, flow control, and header compression. It also strongly types services and messages using Protobuf, which are smaller and faster than JSON or XML.
WebSocket:
Over a single durable TCP connection, WebSocket is a technology that offers full-duplex communication channels. It enables real-time data transfer and is often used for chat programs, real-time gaming, and real-time website information updating. By defining a standard for real-time, two-way communication between a client and server, WebSocket will make it feasible to develop more interactive and dynamic web applications.
Webhook:
A webhook is a tool for adding to or changing the callbacks on a web page or web application. These callbacks might be updated, changed, and handled by independent users and programmers who aren’t always connected to the original website or application. Webhooks are designed to provide data to other applications as it is happening, so you receive info right away. Webhooks convey data as soon as it occurs, acting as an instant data push method in contrast to standard APIs, which require frequent polling to obtain real-time data.
Each of these technologies and approaches serves different needs and has different trade-offs. The choice of technology would depend on your specific use-case and requirements.
Additional resources:
https://www.altexsoft.com/blog/soap-vs-rest-vs-graphql-vs-rpc/
https://nordicapis.com/when-to-use-what-rest-graphql-webhooks-grpc/