Imagine a big office with dozens of departments. Each department is responsible for its own piece of work, and clients have to run between departments to gather all the info. That office is your microservice project, and the clients are the frontend app. Running between departments is your HTTP requests to the REST API. A nightmare, right? This is where GraphQL comes in — it acts like a single information desk where you can request everything through one window.
Single entry point
GraphQL lets you create a single facade for all microservices. All traffic goes through the GraphQL server, which aggregates data from each service. For example:
- User Service stores information about users.
- Order Service is responsible for users' orders.
- Review Service manages product reviews.
Instead of the client requesting data from three separate REST API endpoints, it makes one request to GraphQL. The GraphQL server figures out where to go.
Example architecture with GraphQL
+---------------+ +---------------------+
| CLIENT | --> | GraphQL API |
+---------------+ +---------+-----------+
|
+------------------------+------------------------+
| | |
+---------------+ +---------------------+ +-----------------+
| User Service | | Order Service | | Review Service |
+---------------+ +---------------------+ +-----------------+
Why's this handy? Because the client doesn't need to care where and how data is stored. It only needs to know that the GraphQL API will provide all the necessary information.
Aggregating data from multiple microservices
The REST problem
Say you need to show the user's profile page with:
- The user's name.
- The list of their orders.
- Reviews for those orders.
With REST it looks like this:
- A request is sent to the User Service to get the user's name.
- Based on the user ID, a second request is sent to the Order Service to get orders.
- For each order, requests are sent to the Review Service to get reviews.
That's dozens of requests that take a lot of time and overload the network. It's like going to three stores to put together one dinner.
How GraphQL fixes this
GraphQL lets you combine all that info into a single request. You create a schema that describes the dependencies between data, and the GraphQL server runs the complex logic for you. Example:
query GetUserProfile($userId: ID!) {
user(id: $userId) {
name
orders {
id
items
reviews {
rating
comment
}
}
}
}
The response is a single JSON containing the needed data:
{
"data": {
"user": {
"name": "Ivan Ivanov",
"orders": [
{
"id": "123",
"items": ["item1", "item2"],
"reviews": [
{
"rating": 5,
"comment": "Excellent!"
}
]
}
]
}
}
}
The client doesn't care which sources those data came from — the GraphQL Server already did the work.
Improving the client experience
The Over-fetching and Under-fetching problem
With REST API you either get too much data (over-fetching) or too little (under-fetching). For example:
- You request a list of users, but the REST returns not only names, but addresses, birth dates and other unnecessary data.
- You request a specific user, but the REST API doesn't provide the orders field, and you have to make an extra request.
GraphQL lets clients request exactly what they need. If the UI only needs a list of names, it can request just the name field:
query {
users {
name
}
}
The response will be simple and tidy:
{
"data": {
"users": [
{ "name": "Ivan" },
{ "name": "Maria" },
{ "name": "Petr" }
]
}
}
Benefits for the frontend
- Fewer requests, less lag
Now the client makes just one request instead of three or four, saving network resources. - UI flexibility
If the page design changes and you need to add or remove data, you just change the GraphQL query without modifying server code. - Reactivity
With Subscriptions, GraphQL lets clients receive real-time updates. That's especially useful for notifications, chat systems, and dynamic interfaces.
Practice: setting up microservices with GraphQL
Step 1. Create the schema
Create the file schema.graphqls in your GraphQL server. For example:
type User {
id: ID
name: String
orders: [Order]
}
type Order {
id: ID
items: [String]
reviews: [Review]
}
type Review {
rating: Int
comment: String
}
type Query {
user(id: ID!): User
}
Step 2. Set up resolvers
In the GraphQL server (on Spring Boot) set up resolvers. For example:
@Component
public class UserResolver implements GraphQLQueryResolver {
private final UserService userService;
public UserResolver(UserService userService) {
this.userService = userService;
}
public User getUser(Long id) {
return userService.getUserById(id);
}
}
Now every time you request the user field, the getUser method is called.
Step 3. Data aggregation
If data for the orders and reviews fields live in different microservices, set up Data Fetchers:
@Component
public class OrderDataFetcher implements DataFetcher<List<Order>> {
private final OrderService orderService;
public OrderDataFetcher(OrderService orderService) {
this.orderService = orderService;
}
@Override
public List<Order> get(DataFetchingEnvironment env) {
User user = env.getSource();
return orderService.getOrdersForUser(user.getId());
}
}
Step 4. Testing
Use GraphQL Playground to send queries and check responses. For example:
query {
user(id: 1) {
name
orders {
id
items
reviews {
rating
comment
}
}
}
}
Now you have an idea of how GraphQL becomes an "all-in-one" facade for a microservice system. It simplifies interaction, makes the API accessible and convenient, and gives clients flexibility in queries.
GO TO FULL VERSION