API Design
The End of Over- and Under-fetching
Over the past ten years, REST (Representational State Transfer) has been the de facto standard for designing web APIs. REST operates based on fixed endpoints (e.g. /users/123) where each endpoint returns a fixed structure of data. Although this concept is simple and scalable, it quickly runs into its limits in modern applications — where data from multiple sources must be merged for complex user interfaces. Developers struggle daily with ‘over-fetching’ (retrieving too much redundant data) and ‘under-fetching’ (retrieving too little data, requiring extra network calls to other endpoints such as /users/123/posts).
In 2015, Facebook introduced an elegant solution to this problem: GraphQL. Instead of addressing multiple rigid endpoints, GraphQL offers a single, flexible endpoint. The client (frontend) sends a query describing exactly which data fields it needs, and the server returns exclusively and exactly that requested data.
The Architecture of GraphQL: Types, Queries, and Resolvers
The core of GraphQL is the Schema. The schema, written in the Schema Definition Language (SDL), acts as a binding contract between the frontend and the backend. It defines exactly which objects (Types) are available, which fields they have, and how they are related to each other. Because GraphQL is highly typed, developers can automatically generate documentation and benefit from auto-completion (IntelliSense) in their code editors.
On the backend, the heavy lifting is done by ‘Resolvers’. For each field in the query, the backend developer writes a resolver function responsible for retrieving the data from the underlying sources (SQL databases, NoSQL databases, external APIs, or microservices). This means that GraphQL acts as an abstraction layer (an API Gateway) that completely hides the complexity of the backend infrastructure from the frontend developer.
The N+1 Problem and Data Loaders
Despite the benefits, GraphQL introduces its own technical challenges, the most notorious of which is the ‘N+1 problem’. Because resolvers are executed at the field level, a query requesting a list of 100 articles, along with the name of each article’s author, can result in one initial database query for the articles, followed by 100 separate queries for the authors (N+1). This places an enormous strain on the database and destroys performance.
Enterprise environments solve this by implementing ‘Dataloaders’. A Dataloader is a utility that runs in the backend and collects incoming requests for a few milliseconds (batching), to then process them as one large, optimized IN query (e.g. SELECT * FROM users WHERE id IN (1, 2, 3...)to send to the database. Furthermore, the Dataloader ensures caching within a single request, so that the same author is never retrieved twice.
Security and Caching Challenges
GraphQL is incredibly powerful, but with great power comes great responsibility. Because the client determines the structure of the query, a malicious user can send an infinitely deep nested query (e.g. Author -> Article -> Comment -> Author -> Article...) in an attempt to crash the server (DDoS). Developers must implement security measures such as Query Depth Limiting and Query Cost Analysis to prevent heavy queries from overloading the server.
Additionally, HTTP caching (via CDNs) is more difficult with GraphQL than with REST, because all requests are sent as POST messages to the same endpoint. Tools such as Apollo Server offer advanced solutions for this, such as ‘Persisted Queries’, where the client only sends a hash of the query. GraphQL is not a magic bullet that makes REST obsolete, but for data-intensive frontend applications, it offers an unparalleled development experience. Discover the possibilities of advanced APIs at Frankwatching.
Serverless Architectures and Edge Computing: Beyond the Cold Start
