DEV Community

Cover image for Request/Response APIs: REST vs GraphQL vs OData vs Falcor
Shiv Rai (S_RAI)
Shiv Rai (S_RAI)

Posted on AI-assisted

Request/Response APIs: REST vs GraphQL vs OData vs Falcor

What are Request/Response APIs?

Request/Response APIs are the most common way for applications to communicate across process, network, or service boundaries. A client sends a request for information or an action, and a server returns a response containing the result.

This model is simple, predictable, and well-suited to workloads where a consumer knows when it needs data and expects an immediate answer. Web applications, mobile apps, dashboards, internal tools, and third-party integrations all commonly rely on request/response communication.

Common use cases include:

  • CRUD applications
  • Web and mobile backends
  • Public developer platforms
  • Internal business systems
  • Reporting and analytics APIs
  • Data access layers for enterprise applications

This article includes: REST, GraphQL, Falcor, OData.


How to choose?

  1. Simplicity, interoperability, and widespread ecosystem support -> REST
  2. Clients need flexible access to complex data -> GraphQL
  3. Efficient access to large, connected data graphs -> Falcor
  4. Standardization, querying capabilities, and enterprise integration are primary concerns -> OData
flowchart TD

A[Need a Request/Response API] --> B{Need a standardized query language<br/>for business data and integrations?}

B -->|Yes| O[OData]
B -->|No| C{Do clients need precise control<br/>over returned fields and shapes?}

C -->|No| R[REST]
C -->|Yes| D{Are you building around a<br/>single logical data graph with<br/>heavy client-side navigation?}

D -->|Yes| F[Falcor]
D -->|No| G[GraphQL]

Comparison

Aspect REST GraphQL Falcor OData
Mental Model Resources exposed through endpoints Query a graph of data Navigate a virtual JSON graph Resources enhanced by a standardized query language
Data Fetching Flexibility Low to Medium High High Medium to High
Client Control Limited by endpoints High High Moderate
Complexity Low Medium to High Medium to High Medium
Caching Excellent and well understood More challenging Good with graph-aware tooling Good
Tooling Extremely mature Mature and growing Smaller ecosystem Strong enterprise ecosystem
Learning Curve Low Medium Medium to High Medium
Typical Use Cases Public APIs, web services, CRUD systems Frontend-heavy applications, aggregating multiple data sources Rich data-driven applications with complex relationships Enterprise systems, analytics, business applications
Strengths Simplicity, scalability, broad adoption Flexible queries, reduced over/under-fetching Efficient graph traversal and data reuse Standardized querying and interoperability
Weaknesses Multiple requests for related data, endpoint proliferation Increased operational and schema complexity Smaller adoption and ecosystem Can feel verbose and enterprise-oriented

REST

REST stands for REpresentational State Transfer. It was introduced by Roy Fielding, one of the creators of HTTP. He published his PhD dissertation in 2000 explaining why the World Wide Web scaled so well. According to him, the web succeeded because it followed certain architectural constraints. This architectural style became known as REST.

REST offered a simpler model than the RPC-style communication common between systems at the time:

  • Everything important is a resource
  • Resources have URLs
  • Standard HTTP methods operate on those resources
  • Clients and servers remain loosely coupled

REST isn't a protocol. It's an architectural style.

Note: Strict REST, as originally defined, includes additional constraints such as HATEOAS (Hypermedia as the Engine of Application State). In practice, many APIs commonly referred to as "REST APIs" do not fully implement every constraint from the original definition — what most teams build and call "REST" is closer to resource-oriented HTTP APIs.

REST thinks in resources

A resource is simply a thing your system exposes:

  • Users
  • Books
  • Orders
  • Authors

Instead of:

createUser()
getUser()
deleteUser()
Enter fullscreen mode Exit fullscreen mode

REST is:

POST   /users
GET    /users/123
DELETE /users/123
Enter fullscreen mode Exit fullscreen mode

Examples

Create a user:

Request

POST /users

Content-Type: application/json

{
  "name": "Alice"
}
Enter fullscreen mode Exit fullscreen mode

Response

201 Created

{
  "id": 123,
  "name": "Alice"
}
Enter fullscreen mode Exit fullscreen mode

Fetch a user:

Request

GET /users/123
Enter fullscreen mode Exit fullscreen mode

Response

{
  "id": 123,
  "name": "Alice"
}
Enter fullscreen mode Exit fullscreen mode

A representation of a resource is transferred during calls, not the resource itself.

Pros and Cons

Pros Cons
Simple and easy to understand using standard HTTP methods (GET, POST, PUT, DELETE). Can lead to overfetching (receiving more data than needed).
Universally supported across browsers, servers, mobile apps, proxies, and CDNs. Can lead to underfetching (multiple requests needed to gather related data).
Leverages existing HTTP infrastructure and tooling. No built-in strong typing or schema enforcement.
Cache-friendly through HTTP caching headers and CDN support. API contracts are often documented separately and validated at runtime.
Resource-oriented design maps naturally to CRUD operations. Modeling complex business actions can become awkward.
Stateless architecture improves scalability and reliability. Real-time communication is not natively supported.
Human-readable requests and responses simplify debugging. Versioning strategies can become complicated over time.
Loose coupling between clients and servers allows independent evolution. Deeply nested or relational data often requires multiple round trips.
Easy to test using browsers, curl, Postman, or similar tools. Performance may suffer in chatty client-server interactions.
Large ecosystem, mature best practices, and widespread adoption. Different teams often interpret REST principles differently, leading to inconsistent APIs.

GraphQL

Facebook developed GraphQL internally in 2012 to tackle the difficulty of working with REST APIs as their mobile apps grew. Facebook open-sourced GraphQL in 2015.

Mobile clients often faced problems such as:

  • Slow networks
  • Limited bandwidth
  • Multiple API requests for a single screen
  • Different data requirements across platforms

REST forces the server to decide what data is returned. GraphQL lets the client decide. Instead of many endpoints, GraphQL provides a single endpoint, /graphql, through which all actions take place.

GraphQL thinks in queries

The client describes the exact structure of the response. The client requests fields, and the server assembles the response.

Example

A user has:

id
name
email
avatar
Enter fullscreen mode Exit fullscreen mode

Client only needs name.

Query

query {
  user(id: 123) {
    name
  }
}
Enter fullscreen mode Exit fullscreen mode

Response

{
  "data": {
    "user": {
      "name": "Alice"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Client needs name + email:

Query

query {
  user(id: 123) {
    name
    email
  }
}
Enter fullscreen mode Exit fullscreen mode

Response

{
  "data": {
    "user": {
      "name": "Alice",
      "email": "alice@example.com"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Pros and Cons

Pros Cons
Eliminates overfetching More complex backend architecture
Reduces underfetching and multiple requests Caching is harder than REST
Strong schema and typing Can suffer from N+1 query issues
Excellent tooling and developer experience Query complexity must be controlled
Flexible for multiple client types Overkill for simple CRUD systems
Self-documenting schema Additional learning curve
Easier API evolution Monitoring and performance tuning are harder

Falcor

A note on relevance: Falcor is included here primarily for historical and conceptual understanding — it introduced ideas (like a unified virtual data graph) that are useful for building intuition. In practice, GraphQL became the dominant solution for flexible, client-driven data fetching.

Falcor was created by Netflix and open-sourced in 2015. Netflix applications needed data from many backend services:

Recommendations
User Profiles
Ratings
Viewing History
Search
Metadata
Enter fullscreen mode Exit fullscreen mode

Building a screen often required multiple API calls. This created:

  • Overfetching
  • Underfetching
  • High latency
  • Complex frontend code

Falcor introduced a concept called the JSON Graph. Instead of exposing APIs as resources or functions, the server exposes a graph of interconnected data. The client requests paths through that graph.

Falcor thinks in graphs

Imagine application data as one giant object:

{
  users: {},
  movies: {},
  ratings: {},
  recommendations: {}
}
Enter fullscreen mode Exit fullscreen mode

Clients don't call endpoints. They ask for paths inside the graph.

Example:

users[123].name
movies[42].rating
Enter fullscreen mode Exit fullscreen mode

Core assumption: Application data is a graph, and clients should navigate that graph directly.

Example

Suppose the graph contains:

{
  users: {
    123: {
      name: "Alice"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Client requests:

model.get([
  "users",
  123,
  "name"
]);
Enter fullscreen mode Exit fullscreen mode

Response:

{
  "jsonGraph": {
    "users": {
      "123": {
        "name": "Alice"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Pros and Cons

Pros Cons
Flexible graph-based data access Steeper learning curve
Built-in client caching Small ecosystem
Reduces API round trips Limited adoption
Handles relationships naturally GraphQL largely replaced it
Efficient for connected data Fewer tools and community resources
Client-driven fetching Complex mental model
Good Netflix-scale use cases Rarely chosen for new projects

OData

As organizations exposed more data over HTTP, developers repeatedly faced the same problems:

GET /users
GET /products
GET /orders
Enter fullscreen mode Exit fullscreen mode

Every API invented its own way to support:

  • Filtering
  • Sorting
  • Pagination
  • Searching
  • Expanding related data

Example:

GET /users?status=active
Enter fullscreen mode Exit fullscreen mode

might work in one API, while another used:

GET /users?filter=status:active
Enter fullscreen mode Exit fullscreen mode

There was no standard way to query data over HTTP. OData (Open Data Protocol) was introduced by Microsoft in 2007 and later standardized through OASIS. OData attempted to create SQL-like querying for HTTP APIs. Instead of every API inventing its own query language, clients could use a standard set of query operations.

Clarification — REST vs. OData: Traditional REST APIs usually expose fixed resource representations, meaning the server largely decides what shape a response takes. OData extends REST-style APIs with a standardized querying layer on top, giving clients more control over returned data (filtering, selecting fields, expanding relations) without changing the underlying request/response model.

OData thinks in queryable resources

Core assumption: APIs expose resources the same way REST does, but those resources are enhanced with a standardized query language — so clients can filter, sort, select fields, and expand relations without the server needing to build a custom endpoint for every variation.

Instead of:

GET /active-users
GET /users-by-country
GET /top-customers
Enter fullscreen mode Exit fullscreen mode

you expose:

GET /users
Enter fullscreen mode Exit fullscreen mode

and allow the client to specify the query. The server provides the data. The client decides how to filter it.

Example

Let's say:

GET /users
Enter fullscreen mode Exit fullscreen mode

returns:

[
  {
    "id": 1,
    "name": "Alice",
    "country": "US"
  },
  {
    "id": 2,
    "name": "Bob",
    "country": "IN"
  }
]
Enter fullscreen mode Exit fullscreen mode

Client requests:

GET /users?$filter=country eq 'US'
Enter fullscreen mode Exit fullscreen mode

Response:

[
  {
    "id": 1,
    "name": "Alice",
    "country": "US"
  }
]
Enter fullscreen mode Exit fullscreen mode

Pros and Cons

Pros Cons
Powerful built-in querying Query language complexity
Standardized filtering and sorting Can expose expensive operations
Reduces endpoint proliferation Tight coupling to data models
Metadata discovery support Less flexible than GraphQL
Great for business datasets Smaller ecosystem
Strong enterprise tooling Rarely used for public APIs
HTTP and REST friendly Requires careful security controls

Key Takeaways

  • Choose REST when you want simplicity, broad tooling support, strong HTTP caching, and your data access patterns are mostly straightforward CRUD.
  • Choose GraphQL when clients have varied or evolving data needs, over/underfetching is a real problem, and you can support the added backend complexity.
  • Choose OData when you need standardized, SQL-like querying (filtering, sorting, expanding relations) over business data, especially in enterprise or Microsoft-adjacent ecosystems.
  • Choose Falcor rarely, if ever, for new projects — it's mainly useful for understanding the "unified data graph" mental model.

Top comments (0)