GraphQL is a data query language developed by Facebook, designed to make APIs faster, more flexible, and more developer-friendly.
Unlike REST API, it allows clients to define the structure of the data they need and receive the desired information with a single request. It also uses a type system to clearly define the data structure of requests and responses, enhancing code stability.
"You can get only what you want, just as much as you need" is its most significant feature.
REST API 🆚 GraphQL
Let's assume there's a REST API that contains country information. To retrieve a list of countries, let's call the /countries
endpoint.
/countries
// GET /countries response
[
{
"code": "AD",
"name": "Andorra",
"capital": "Andorra la Vella",
"region": "Europe"
},
{
"code": "AE",
"name": "United Arab Emirates",
"capital": "Abu Dhabi",
"region": "Asia"
},
{
"code": "AF",
"name": "Afghanistan",
"capital": "Kabul",
"region": "Asia"
},
// ... more than 200 country data
]
We've found out a country's unique ID code. Now, if we want to know more detailed information about that country, we need to call another API.
/countires/KR
// GET /countries/KR response
{
"code": "KR",
"name": "South Korea",
"native": "대한민국",
"phone": "82",
"capital": "Seoul",
"currency": "KRW",
"languages": ["ko"],
"emoji": "🇰🇷",
"region": "Asia",
"subregion": "Eastern Asia",
"states": [
{ "name": "Seoul", "code": "11" },
{ "name": "Busan", "code": "26" },
{ "name": "Incheon", "code": "28" },
// ... more regions
]
}
What's the problem with this approach?
- Over fetching problem: If we only need to show the country name and capital, we don't need to fetch other information. However, when we call the API, we receive all data for all countries. As the amount of data increases, the amount of traffic increases, which can lead to performance degradation.
- Under fetching problem: To show detailed country information, two API calls are needed. Therefore, to show countries and their detailed information together, multiple API calls are required.
Solution through GraphQL
The problems of REST API listed above can be solved with GraphQL as follows:
- All requests can be handled through a single endpoint. This simplifies management and maintenance.
- Clients can request only the data they need. The client can specify the structure of the needed data, reducing unnecessary data transmission and increasing network efficiency.
🆚 /countries
query {
countries {
name
capital
emoji
}
}
Response
{
"data": {
"countries": [
{
"name": "Andorra",
"capital": "Andorra la Vella",
"emoji": "🇦🇩"
},
{
"name": "United Arab Emirates",
"capital": "Abu Dhabi",
"emoji": "🇦🇪"
},
{
"name": "Afghanistan",
"capital": "Kabul",
"emoji": "🇦🇫"
},
// ... more countries
]
}
}
🆚 /countries/KR
query {
country(code: "KR") {
name
native
capital
emoji
currency
languages {
name
native
}
continent {
name
}
}
}
Response
{
"data": {
"country": {
"name": "South Korea",
"native": "대한민국",
"capital": "Seoul",
"emoji": "🇰🇷",
"currency": "KRW",
"languages": [
{
"name": "Korean",
"native": "한국어"
}
],
"continent": {
"name": "Asia"
},
}
}
}
We got all the information we needed with just one request! 🫢
Advantages of GraphQL
1. Single Endpoint
One of the features of GraphQL is that it uses only one endpoint. In REST API, different endpoints were needed for each resource, such as /countries
, /countries/KR
, /countries/KR/borders
, /languages
, but GraphQL typically uses only a single URL, usually /graphql
.
- Simplified frontend development: Developers only need to know one endpoint instead of remembering multiple endpoints or looking up documentation.
- Enhanced security: Only one entry point needs to be protected, allowing authentication and authorization logic to be centralized.
2. Request Only the Data You Need (Solving Over fetching)
With GraphQL, clients can request exactly the data they need. This can solve the over fetching problem.
- Reduced network traffic: Bandwidth usage is reduced by not transmitting unnecessary data.
- Improved response time: Server response time can be improved by processing only the needed data.
3. Fetch Related Data with a Single Request (Solving Under fetching)
With GraphQL, data from multiple resources can be fetched with a single request. This can solve the under fetching problem.
- Reduced network requests: All data is fetched with one request instead of multiple API calls.
- Elimination of waterfall-style requests: Sequential API calls common in REST are not needed.
- Simplified frontend code: Complex code to coordinate multiple API calls is not needed.
4. Powerful Type System
GraphQL is based on a strict type system. Each field's type is clearly defined, greatly enhancing the stability and predictability of the API.
- Compile-time error detection: Type errors can be detected during development.
- Automatic code generation: Client code can be automatically generated based on type definitions (e.g., TypeScript interfaces).
- Enhanced IDE support: Development environment support is enhanced with code auto-completion, type checking, etc.
- Clear contract: A clear data contract is formed between frontend and backend.
Disadvantages of GraphQL
1. Complex Query Processing Burden
GraphQL provides query flexibility to clients, but this can create a burden on the server side.
- Performance impact of complex queries: Very nested queries or complex queries requesting multiple resources can put a heavy load on the server.
query NestedQuery {
continents {
countries {
languages {
countries {
languages {
countries {
...
}
}
}
}
}
}
}
- Resource attack possibility: Malicious users can intentionally send very complex queries that consume server resources.
2. Complexity of Caching Implementation
REST APIs can be easily cached based on URLs, but GraphQL requires more complex caching strategies.
3. Differences in Error Handling
- Lack of HTTP status code utilization: Errors are included in the response body, which can be tricky to handle.
- Partial failure handling: Only part of a query may fail, so clients need to handle partial success/failure scenarios.
- Error debugging: Debugging can be more difficult when problems occur in complex queries.
4. Risks of Excessive Flexibility
The flexibility of GraphQL can be a double-edged sword.
- API version management confusion: Fields can be easily added, which may lead to a lack of explicit version management.
- Increasing query complexity: Client queries may become increasingly complex over time.
- Backend logic exposure: Flexible queries may unintentionally expose internal system structures.
- Difficulty in understanding API usage patterns: Various client query patterns can make it difficult to identify the most important data and fields.
GraphQL Basic Types
One of the powerful features of GraphQL is its type system. Let's look at what types are available.
Type | Description |
---|---|
String | UTF-8 string |
ID | Basically a String, but indicates it serves as a unique identifier |
Int | Signed 32-bit integer |
Float | Signed floating-point value |
Boolean | True/False |
!(Non Null)
Indicates that a specific field cannot contain null
.
Example
const typeDefs = gql`
type Supplies {
id: ID!
name: String!
price: Int
}
`
enum (Enumeration Type)
A type that returns one of the pre-specified values.
const typeDefs = gql`
enum Role {
developer
designer
planner
}
enum NewOrUsed {
new
used
}
`
[] (Array Type)
Indicates that a specific type is an array.
const typeDefs = gql`
type Foods {
ingredients: String[]
}
`
Also, the position of !
can indicate different meanings.
Declaration | users: null | users: [ ] | users: [..., null] |
---|---|---|---|
[String] | ✔ | ✔ | ✔ |
[String!] | ✔ | ✔ | ❌ |
[String]! | ❌ | ✔ | ✔ |
[String!]! | ❌ | ✔ | ❌ |
union Type
Used when you want to bundle multiple written types together.
const typeDefs = gql`
union Given = Equipment | Supply
`;
interface Type
A type for creating similar object types, written for implements. An error occurs if a field from the interface is not implemented in the inheriting object.
interface Produce {
id: ID!
name: String!
quantity: Int!
price: Int!
}
# OK
type Fruit implements Produce {
id: ID!
name: String!
quantity: Int!
price: Int!
}
# ERROR !!
type Vegetable implements Produce {
id: ID!
name: String!
quantity: Int!
}
input Type
Can specify the type of parameters that should go into a query or mutation.
input PostPersonInput {
first_name: String!
last_name: String!
}
type Mutation {
postPerson(input: PostPersonInput): People!
}
When Should You Choose GraphQL?
GraphQL is a powerful tool for creating more flexible and efficient APIs. While REST API is still a good choice in many situations, GraphQL can provide clear advantages in situations with complex data requirements and support for various clients.
However, remember that GraphQL is not a universal solution, but a tool that fits certain situations. It's important to analyze your project's requirements well and choose between REST API and GraphQL accordingly.
GraphQL may be a good choice in the following situations:
- Applications with complex data relationships
- Like a country information app with complex relationships between multiple entities
- Social networks with various relationships between users, posts, comments, likes, etc.
- Need to support various clients
- Different data requirements on various platforms such as web, mobile apps, desktop, etc.
- When each client needs to fetch customized data from the same backend
- When rapid product iteration and frontend development speed are important
- When frontend requirements need to be easily accommodated without backend changes
- Startups or agile environments where user interfaces and features change frequently
- When microservice integration is needed
- When data from multiple microservices needs to be integrated into a single consistent API
- When implementing the BFF (Backend For Frontend) pattern
Situations Where REST is Still Appropriate
REST API may be more appropriate in the following situations:
- When simple CRUD operations predominate
- Applications with simple data structures and few relationships
- When data request patterns are consistent and predictable
- When HTTP caching is important
- Situations where efficient HTTP caching is important, such as public APIs
- When caching through CDN is a key performance factor
- When file upload is a main feature
- When large file processing and streaming are key requirements
- When the team's learning curve needs to be minimized
- When the team is familiar with REST and time to learn a new paradigm is limited
Conclusion
Like all technologies, GraphQL also comes with specific trade-offs. In the end, the most important thing is to meet the requirements of users and businesses. Whether it's GraphQL, REST, or a combined approach, let's choose the technology that fits the specific situation and goals of the project!
References