API Communication
REST
Introduction to REST: REST (Representational State Transfer) is a software architectural style that defines a set of constraints for creating stateless web services.
It is based on stateless communication between clients and servers using HTTP.
A RESTful service exposes resources (data objects) identified by URIs.
Clients interact with resources using HTTP methods/HTTP Verbs (GET, POST, PUT, DELETE).
Resource representations are typically in JSON, but XML or HTML can also be used.
Typical REST Workflow:
Client sends an HTTP request to the server.
Server processes the request.
Server returns a representation of the resource (e.g., JSON).
Client performs CRUD operations based on the resource.
REST Principles
Resource-Oriented:Everything in REST is a resource (e.g., users, posts, images).
Each resource is uniquely identified by a URL.
Representation: Can have multiple representations (e.g., JSON, XML).
Identifier (URI): A Uniform Resource Identifier (URI) is a unique address to access a resource. Example: /users/123
Metadata: Additional information about resources such as:
Content-Type: Specifies the format (JSON, XML, etc.).
Last-Modified: Indicates when the resource was last updated.
Content-Type: application/json
Cache-Control: no-cache
Control Data: Used to manage caching, authentication, and modification policies.
Example: Cache-Control: max-age=3600 allows a resource to be cached for 1 hour.
HTTP Methods in REST: REST APIs use HTTP methods to perform operations on resources.
HTTP Method
Purpose
Example
GET
Retrieve a resource
GET /users/123
POST
Create a new resource
POST /users
PUT
Update an existing resource
PUT /users/123
PATCH
Modify part of a resource
PATCH /users/123
DELETE
Remove a resource
DELETE /users/123
HEAD
Fetch metadata only (no body)
HEAD /users/123
OPTIONS
Retrieve allowed methods for a resource
OPTIONS /users
REST Constraints: To be RESTful, a web service must follow these six constraints:
Client-Server Separation: The client and server must be independent.
The client only requests data, and the server responds with it.
Stateless: The server does not store any information about the client between requests.
Each request must contain all required authentication and state information.
Cacheable: Responses should be cacheable to reduce server load.
Example: If an API response contains a Cache-Control header, the client can cache it.
Uniform Interface: The API should have a consistent structure:
Identification of resources via URIs.
Manipulation of resources via HTTP methods.
Self-descriptive messages including metadata.
HATEOAS (Hypermedia as the Engine of Application State): API responses include links to related resources.
Layered System: The architecture can have multiple layers (e.g., security, caching, load balancing).
The client should not know how many layers exist between it and the actual server.
Code-on-Demand: The server can send executable code (JavaScript) to the client.
REST API Design Best Practices:
Use Nouns in URIs: /users instead of /getUsers
Use Plural Nouns for Collections: /books instead of /book
Use Sub-Resources for Relationships:
/users/123/orders instead of /orders?user=123
/customers/1/orders → orders for a customer
/orders/99/products → products in order 99
Collections should be exposed as top-level resources.
Don’t go too deep with nesting (e.g., /a/b/c/d/e)—it becomes hard to consume and maintain.
Use HTTP Headers for Format Negotiation:
Accept: application/json
Content-Type: application/xml
Provide Filtering & Pagination:
/orders?minCost=50&limit=10&offset=20
Use Versioning: /v1/users or version in headers/query parameters.
Meaningful Errors:
401 Unauthorized
404 Not Found (Resource does not exist)
REST is not about tables or fields, but about:
Conceptual resources
Use cases
Client usability
Example: An Order resource may be composed from multiple database tables (customer, item, shipment) but is represented as a single, unified JSON object to the client.
API Versioning: API versioning allows multiple versions of an API to coexist, so that changes don't break existing clients.
APIs evolve. But changes can break existing client apps. Versioning ensures:
Old clients still work.
New clients can use new features.
The API contract remains reliable.
Versioning Strategies
URL Path Versioning: The version number is part of the URL.
GET /v1/users/123, GET /v2/users/123
Custom Header Versioning: Clean URLs; Version information is sent in the HTTP header.
X-API-Version: 2
Query Parameter Versioning: Version is specified as a query string.
GET /users/123?version=1
Content Negotiation: When media types change across versions
Accept: application/vnd.example.v1+json
Change Management Strategy:
Principle
Description
Add, don’t remove
Introduce new fields, don’t break old ones
Sunset obsolete parts
Phase out with proper warnings
Track change scope
Use tree analogy
Tree Analogy of API Change Scope: As you move from leaf to root, changes become more global and disruptive.
Level
Description
Leaf
Minor isolated endpoint change
Branch
Changes across related resources
Trunk
System-wide schema change
Root
Impacts all API versions and resources
Types of Breaking Changes:
Change Type
Example
Format change
XML → JSON
Field rename
name → productName
Data type change
int → float
Add required field
Adding email to required inputs
Remove field
Removing description from response
Semantic Versioning for APIs:
Format: MAJOR.MINOR.PATCH
But in APIs, often simplified to: BREAKING.NONBREAKING
BREAKING: Any change that could break existing clients
NONBREAKING: Additions, enhancements, backward-compatible changes
Example: Version 2.1 means: second major version, first set of safe enhancements.
This versioning strategy helps consumers know how risky it is to adopt a newer version.
API Documentation: API documentation tells developers what endpoints are available, what data they need, and what to expect in return.
Explains how to use and integrate with an API.
Helps developers adopt, test, and trust your API.
Should be clear, accurate, interactive, and up-to-date.
OpenAPI Specification (OAS): Formerly Swagger Spec, now maintained by the Linux Foundation; Industry standard tools to define, document, and test APIs interactively.
Written in YAML or JSON.
OAS Describes:
All endpoints (e.g., /users, /products)
Methods per endpoint (GET, POST, etc.)
Input/output schemas
Security/auth methods
Metadata like contact info, license
Can be used to auto-generate:
API docs (Swagger UI)
Client SDKs
Server code
Swagger Tools (Now OpenAPI Tools):
Tool
Use
Swagger Editor
Create & edit OpenAPI specs
Swagger UI
Render interactive API docs
Swagger Codegen
Generate client/server code
SwaggerHub
Collaborative API design
Good API Docs Should Include:
Clear endpoint descriptions
Sample requests/responses
Status codes
Authentication details
Required/optional parameters
API Documentation Formats:
Format
Maintained By
Language
RAML (RESTful API Modeling Language)
MuleSoft (Salesforce)
YAML
API Blueprint
Apiary (Oracle)
Markdown
OpenAPI (formerly Swagger)
Linux Foundation
YAML/JSON
REST Maturity Model: The REST Maturity Model helps evaluate how RESTful an API is, based on four levels (0 to 3). Each level builds upon the previous one, improving the use of REST principles.
Level 0 –
All requests are sent to a single endpoint (e.g., /api) using a single HTTP method (often POST).
No use of resources or proper HTTP methods.
Level 1 – Resources
Introduces the idea of resources (e.g., /users, /orders). Each resource has a unique URI.
Still usually uses only one HTTP method (like POST).
Level 2 – HTTP Methods
Uses standard HTTP methods correctly. Improves clarity and aligns with REST principles.
Level 3 – (HATEOAS) - Hypermedia As The Engine Of Application State
Includes links in responses to related actions/resources. Enables navigation.
Implementing REST APIs in Frameworks: Common backend frameworks (Spring Boot, Express.js, Django REST, etc.) offer:
Routing and URL mapping
Request parsing and response formatting
Model binding and ORM integration
Using Express.js (Node.js Example):
const express = require('express'); const app = express(); app.get('/products/:id', (req, res) => { res.json({ id: req.params.id, name: 'Pen', price: 10 }); }); app.listen(3000, () => console.log('Server running on port 3000'));
Common HTTP Status Codes:
Code
Status Text
Meaning
200
OK
The request has succeeded.
201
Created
A new resource has been successfully created.
202
Accepted
The request has been accepted for processing, but the process is not completed yet.
204
No Content
The request was successful but there is no response body.
206
Partial Content
Used when serving partial GET requests (e.g., for large file downloads).
301
Moved Permanently
Resource has a new permanent URI.
302
Found
Temporarily moved.
304
Not Modified
Use cached response; server content hasn't changed.
400
Bad Request
The server cannot process the request due to client-side errors (malformed syntax).
401
Unauthorized
Authentication is required or has failed.
403
Forbidden
The client is authenticated but not authorized to access the resource.
404
Not Found
The requested resource could not be found on the server.
405
Method Not Allowed
The requested method (e.g., PUT) is not allowed on this resource.
406
Not Acceptable
The resource exists, but it can't be returned in a format acceptable to the client (based on the Accept header).
409
Conflict
Request conflicts with server state (e.g., trying to create a duplicate resource).
415
Unsupported Media Type
Client sends data in an unsupported format (e.g., Content-Type: text/plain when API expects JSON).
422
Unprocessable Entity
Semantic errors in the request (used in validation).
429
Too Many Requests
Rate-limiting: client has sent too many requests in a short time.
500
Internal Server Error
A generic error indicating a server-side problem.
502
Bad Gateway
Server acting as a gateway received an invalid response from the upstream server.
503
Service Unavailable
Server is overloaded or under maintenance.
504
Gateway Timeout
Server acting as a gateway didn’t get a response in time.
GRPC
Traditional RPC approaches had problems:
Tight coupling with specific languages.
Low performance with text-based formats (like XML or JSON).
Lack of interoperability in distributed microservices.
gRPC in High Level:
Feature
Benefit
Uses Protocol Buffers
Compact and fast binary serialization
Built on HTTP/2
Multiplexed streams, low latency
Cross-platform
Works across multiple languages
Supports Streaming
Real-time communication
Contract-first approach
Defined via .proto files
Auto code generation
Developer productivity and consistency
gRPC Overview: Stands for Google Remote Procedure Call , although the "g" has flexible interpretations.
A modern, open-source, high-performance RPC (Remote Procedure Call) framework.
gRPC enables clients to call functions on remote servers as if they were local method calls.
Example: A mobile app that needs to get the current stock price of a company, instead of making a direct HTTP request to a web server and parsing JSON, It uses gRPC to call a GetStockPrice function on a remote stock price service (server). gRPC handles the networking details, and the app receives the stock price in a structured format.
gRPC Architecture & Workflow: This involves defining a service, generating server and client code, and the server handling requests.
Service Definition (.proto file): Defines the API contract using Protocol Buffers.
Specifies methods (e.g., GetStockPrice) and data structures (e.g., StockRequest, StockResponse).
service StockService { rpc GetStockPrice (StockRequest) returns (StockResponse); } message StockRequest { string symbol = 1; // Field ID 1: Stock symbol (e.g., "AAPL") } message StockResponse { float price = 1; // Field ID 1: Current stock price (e.g., 175.32) }
Both client and server agree on this schema.
Code Generation: Using the .proto file, we run a tool called protoc(the Protocol Buffer Compiler), and it generates code for both client and server.
Generates server-side code (e.g., in Java) with an interface to implement the GetStockPrice function, and client-side code with a stub to call that function.
Server Implementation: The server implements the defined service (e.g., fetching stock price data).
Client Call: The client invokes the method (e.g., GetStockPrice("GOOG")) using the generated stub. gRPC delivers it to the server, which processes it and returns the result.
Steps to Use a gRPC Service
Define service in .proto file.
Use protoc to generate client/server code.
Implement server logic by overriding the generated base class.
Use the client stub to call remote methods like local ones.
Protocol Buffers(Protobuf): Defines structure of data exchanged between client and server.
Protocol Buffers are the default Interface Definition Language (IDL) and serialization format used by gRPC.
Messages = Data structures with fields.
Services = Collections of RPC methods.
Much faster and more compact than JSON or XML.
Example: In the StockService, StockRequest and StockResponse are defined using Protocol Buffers. This ensures that both the client and server agree on the format of the stock symbol and price.
Advantages of gRPC
Efficiency: Uses HTTP/2 with multiplexing and header compression.
Strong Typing: Enforced by Protobuf schema.
Contract-First: Interface is defined before implementation.
Polyglot Support: Works with many languages.
Streaming Support: Bidirectional streaming for real-time use cases.
Rich Tooling: Includes protoc and debugging tools.
Disadvantages of gRPC
Not Ideal for External APIs: Browsers work better with REST + JSON.
Setup Complexity: More complex than basic HTTP APIs.
Service Definition Changes: Require regen and redistribution.
Still Evolving: Tooling and ecosystem less mature than REST.
Message Encoding(via Protocol Buffers):Data is encoded as a binary format, not text.
Each field is represented by a tag number, not the name.
Much faster to transmit and parse.
Example: symbol = "GOOG" is encoded using its tag and value in binary.
Message Framing: gRPC sends multiple messages over a single connection (via HTTP/2).
"Message framing" is the technique gRPC uses to separate these messages, so the receiver knows where one message ends and the next one begins.
Steps:
Encode the message using Protobuf.
Compute the message size in bytes.
It sends this binary representation of the size first.
Then, it sends the actual encoded message data.
Example: If message size = 25 bytes
gRPC sends: [binary(25)] [actual 25-byte message]
Receiver reads length, then reads the next 25 bytes as the message.
gRPC and HTTP/2: gRPC uses HTTP/2, enabling:
Multiplexing: Multiple messages over one connection.
Binary framing.
Header compression.
Example: Multiple concurrent stock price requests via a single HTTP/2 connection.
gRPC Communication Patterns: These are the different ways a client and server can interact.
Unary RPC: A single request, single response.
Example: The client sends a stock symbol using GetStockPrice, and the server sends back the price.
Server-Streaming RPC: Single request, stream of responses.
Example: A GetStockPriceHistory function. The client sends a stock symbol, and the server sends back a stream of historical prices for that stock over a period of time.
Client-Streaming RPC: Stream of requests, single response.
Example: An UpdateStockPrices function. The client sends a stream of stock symbols and their latest prices, and the server sends back a single response indicating success or failure of the update.
Bidirectional-Streaming RPC: Stream of requests, stream of responses.
Example: A real-time stock trading service. The client sends a stream of buy/sell orders, and the server sends back a stream of updates on order execution, price changes, etc.
Tools:
Tool/Resource
Description
grpc.io
Official docs and tutorials
protoc
Compiler for .proto files
Postman with gRPC
Supports gRPC testing (beta)
BloomRPC
GUI tool for gRPC like Postman
Define Service in a .proto file (stock.proto)
syntax = "proto3"; package stock; // The request message containing the stock symbol message StockRequest { string symbol = 1; } // The response message containing the stock price message StockResponse { double price = 1; } // The Stock service definition service StockService { rpc GetStockPrice (StockRequest) returns (StockResponse); }
GraphQL
GraphQL is a query language for APIs and a server-side runtime for executing those queries.
Developed by Facebook in 2012 and open-sourced in 2015.
It allows clients to precisely specify the data they need—nothing more, nothing less.
Key Characteristics:
Declarative: You ask for what you want.
Hierarchical: Mirrors your front-end view structure.
Strongly typed: Backed by a strict type system (schemas).
GraphQL uses a single endpoint for all data needs.
REST Limitation:
Overfetching: You get more data than needed. Example: /users returns full user details when you just need names.
Underfetching: You get less than needed and must make multiple requests.
Too many endpoints: Every new client requirement may need a new endpoint (/user-basic, /user-details).
GraphQL solves this with a single query that returns exactly what is needed.
A GraphQL operation can be:
Query – to read/fetch data
Mutation – to write/modify data
Subscription – to receive real-time data
Lifecycle:
The GraphQL service receives a request.
It validates the query against its schema.
It resolves the query using functions (called resolvers).
Returns data in JSON format.
Example:
query { posts { title author { name email } } }
Response:
{ "data": { "posts": [ { "title": "Introduction to GraphQL", "author": { "name": "John Doe", "email": "john.doe@example.com" } } ] } }
Queries with Arguments and Variables: GraphQL queries support arguments and variables to customize data fetching.
Example:
query getPerson($personid: ID!) { human(id: $personid) { name height(unit: FOOT) } }
Variables:
{ "personid": "1000" }
Queries - Advanced Features
Default Values: Set fallback values for variables.
Directives: Dynamic behavior like @include or @skip.
Fragments: Reusable sets of fields to reduce duplication.
Example:
fragment userInfo on User { name email }
Mutations: Modifying Data:
Just like queries, but used for write operations.
GraphQL gives full control over what is returned after a write.
Each mutation defines:
Input arguments
Returned data (you define what you want back)
Example:
mutation { addUser(name: "Alice", age: 30) { id name age } }
Schema and Types: The schema is the contract between the frontend and backend.
Schema defines:
Types of data (e.g., User, Post)
Relationships between types
Entry points: Query, Mutation, and optionally Subscription
! indicates non-nullable.
ID, String, Int, Boolean, Float are scalar types.
Example:
type User { id: ID! name: String! age: Int }
Query and Mutation Types: Every GraphQL schema defines two special types:
Query: Entry point for data fetching
Mutation: Entry point for data modification
Example:
const schema = buildSchema(` type User { id: ID! name: String! age: Int } type Query { getUser(id: ID!): User getUsers: [User] } type Mutation { addUser(name: String!, age: Int!): User } `);
Resolvers: Connecting Schema to Data: Resolvers are backend functions that define how to fetch or modify data for a type/field.
Each field in a schema has a resolver function.
Resolvers can pull data from:
Databases (SQL, MongoDB, etc.)
REST APIs
External services
Example:
const resolvers = { Query: { getUser: (_, { id }) => db.findUserById(id), }, Mutation: { addUser: (_, { name, age }) => db.addUser(name, age), } };
GraphQL as a Graph
GraphQL is based on graphs: nodes (types) and edges (relationships).
Think of the schema as a map of your entire data model.
Example:
User → Posts
Post → Comments
Comment → Author
GraphQL lets you traverse the graph in a single query.
GraphQL Document Language: GraphQL queries and mutations are written in a specific document language.
A document can contain:
One or more operations
Fragments
Variables
Example:
query GetUser { user(id: "1") { ...userInfo } } fragment userInfo on User { name email }
Tools for Working with GraphQL:
Tool
Purpose
GraphiQL
In-browser IDE for GraphQL
Apollo Client/Server
End-to-end GraphQL solution
GraphQL Playground
Feature-rich tool for testing GraphQL queries
Hasura
Instant GraphQL APIs on Postgres
Postman
Also supports GraphQL APIs for testing
Facebook’s social graph is a literal graph of people and their relationships.
GraphQL mirrors this structure, making it ideal for social networks, eCommerce, dashboards, etc.
Concept
Description
GraphQL
A query language for APIs
Operations
Query (read), Mutation (write), Subscription (live updates)
Schema
Blueprint of types and fields
Types
Define shape of data (User, Post, etc.)
Resolvers
Connect schema fields to real data
Advantages
Precise queries, fewer endpoints, flexible responses
Core Concepts
Arguments, variables, fragments, directives
Last updated