How GraphQL Solves Over Fetching

An HTTP Rest API is the traditional way of fetching data from the server, for each endpoints, it has a fixed contract, which will be returned as the response of the API Call. for some clients the entire response data is necessary, but for some, only a few variables may required, since REST API architecture returns all the data, the client has to accept and parse the entire response data this is also called as Over-fetching, so let's see How GraphQL Solves Over Fetching

GraphQL allows an API consumer to request the required specific data from the server and nothing else, GraphQL will return that response only.

GraphQL provides API consumers an option to request what is required as the below API query

query FindApple {
    findApple {
        appleName
        vendors {
            vendorName
        }
        stores {
            storeName
        }
    }
}

 Let's understand How GraphQL Solves Over Fetching with an Example

The below program provides an API endpoint/findApple which provides details of Apple object along with a List of  Vendor and List of Store details.

 

Rest End Point   Response
http://localhost:8080/findApple

 

 
{
    "appleId": 1,
    "appleName": "MACINTOSH",
    "available": false,
    "price": 1.0,
    "vendors": [
        {
            "vendorId": 1,
            "appleId": 1,
            "vendorName": "Kerrie Armstrong",
            "available": true
        },
        {
            "vendorId": 2,
            "appleId": 2,
            "vendorName": "Demarcus Brakus V",
            "available": true
        },
        {
            "vendorId": 3,
            "appleId": 3,
            "vendorName": "Pete Abshire",
            "available": true
        }
    ],
    "stores": [
        {
            "storeId": 1,
            "appleId": 1,
            "storeName": "Thiel Inc",
            "storeAddress": "Suite 325 689 Doyle Key, Tremblayfort, NM 31598-9515"
        },
        {
            "storeId": 2,
            "appleId": 2,
            "storeName": "Kuvalis Inc",
            "storeAddress": "0984 Johnson Ranch, Lake Juliuston, KY 27051"
        },
        {
            "storeId": 3,
            "appleId": 3,
            "storeName": "Green, Hilll and Reichel",
            "storeAddress": "Apt. 568 3330 Nader Crossroad, Kilbackhaven, NH 65109"
        }
    ]
}

The GraphQL controller allows the client to request only the required parameters

GraqlQL Query GraphQL Response
query FindApple {
    findApple {
        appleName
        vendors {
            vendorName
        }
        stores {
            storeName
        }
    }
}
{
    "data": {
        "findApple": {
            "appleName": "MACINTOSH",
            "vendors": [
                {
                    "vendorName": "Kerrie Armstrong"
                },
                {
                    "vendorName": "Demarcus Brakus V"
                },
                {
                    "vendorName": "Pete Abshire"
                }
            ],
            "stores": [
                {
                    "storeName": "Thiel Inc"
                },
                {
                    "storeName": "Kuvalis Inc"
                },
                {
                    "storeName": "Green, Hilll and Reichel"
                }
            ]
        }
    }
}

Let's see the Spring Boot GraphQL program for the same

package org.wesome.graphql.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import org.wesome.graphql.entity.Apple;
import org.wesome.graphql.service.AppleService;

import java.util.Optional;

@Controller
public record AppleGraphQLController(@Autowired AppleService appleService) {
    @QueryMapping("findApple")
    Optional<Apple> findApple() {
        return appleService.findApple();
    }
}
package org.wesome.graphql.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.wesome.graphql.entity.Apple;
import org.wesome.graphql.service.AppleService;

import java.util.Optional;

@RestController
public record AppleRestController(@Autowired AppleService appleService) {
    @GetMapping(path = "/findApple", produces = "application/json")
    Optional<Apple> findApple() {
        return appleService.findApple();
    }
}
package org.wesome.graphql.data;

public enum AppleType {
    MACINTOSH, FUJI, GALA, JONAGOLD
}
package org.wesome.graphql.entity;

public record Apple(int appleId, String appleName, Boolean available, Float price) {
}
package org.wesome.graphql.entity;

public record Store(int storeId, int appleId, String storeName, String storeAddress) {
}
package org.wesome.graphql.entity;

public record Vendor(int vendorId, int appleId, String vendorName, Boolean available) {
}
package org.wesome.graphql.service;

import org.wesome.graphql.entity.Apple;

import java.util.Optional;

public interface AppleService {
    Optional<Apple> findApple();
}
package org.wesome.graphql.service;

import org.springframework.stereotype.Service;
import org.wesome.graphql.entity.Apple;

import java.util.Optional;

import static org.wesome.graphql.GraphqlProjectApplication.apple;

@Service
public record AppleServiceImpl() implements AppleService {
    @Override
    public Optional<Apple> findApple() {
        return Optional.of(apple);
    }
}
package org.wesome.graphql;

import com.github.javafaker.Faker;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.wesome.graphql.data.AppleType;
import org.wesome.graphql.entity.Apple;
import org.wesome.graphql.entity.Store;
import org.wesome.graphql.entity.Vendor;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;


@SpringBootApplication
public class GraphqlProjectApplication implements CommandLineRunner {
    public static Apple apple;
    public static List<Vendor> vendors;
    public static List<Store> stores;

    public static void main(String[] args) {
        SpringApplication.run(GraphqlProjectApplication.class, args);
    }

    @Override
    public void run(String... args) {
        Faker faker = new Faker();
        vendors = IntStream.rangeClosed(1, AppleType.values().length - 1).mapToObj(value -> new Vendor(value, value, faker.name().fullName(), faker.random().nextBoolean())).collect(Collectors.toList());
        stores = IntStream.rangeClosed(1, AppleType.values().length - 1).mapToObj(value -> new Store(value, value, faker.company().name(), faker.address().fullAddress())).collect(Collectors.toList());
        apple = new Apple(1, AppleType.MACINTOSH.name(), faker.random().nextBoolean(), Float.valueOf(1), vendors, stores);
    }
}

\src\main\resources\graphql\schema.graphqls

# Apple Object
type Apple{
    # primary key of apple
    appleId:ID!
    # apple Name
    appleName:String!
    # apple availability
    available: Boolean
    # apple Price
    price:Float
    # Vendor list
    vendors:[Vendor]
    # stores List
    stores:[Store]
}
# Store Object
type Store{
    # primary key of store
    storeId:ID!
    # primary key of apple
    appleId:ID!
    # apple Store Name
    storeName:String!
    # apple store Address
    storeAddress:String!
}
# Store Object
type Vendor{
    # primary key of vendor
    vendorId:ID!
    # primary key of apple
    appleId:ID!
    # apple vendor Name
    vendorName:String!
    # vendor availability
    available: Boolean
}

# Apple Query
type Query{
    # query to get all Apples
    findApple:Apple
}

\src\main\resources\application.properties

spring.graphql.graphiql.enabled=true
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.5</version>
        <relativePath/>
    </parent>
    <groupId>org.wesome</groupId>
    <artifactId>spring-boot-graphql</artifactId>
    <version>0.0.1-snapshot</version>
    <name>spring-boot-graphql</name>
    <description>implementing graphql in spring boot</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-graphql</artifactId>
        </dependency>
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-java-extended-scalars</artifactId>
            <version>21.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webflux</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.graphql</groupId>
            <artifactId>spring-graphql-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.github.javafaker</groupId>
            <artifactId>javafaker</artifactId>
            <version>1.0.2</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

how to access Rest API

cURL

cURL command is very useful for checking the API endpoint. The rest endpoint can be accessed via curl

API Rest End Point Curl
findApple
http://localhost:8080/findApple
curl --location --request GET "http://localhost:8080/findApple"

 

how to access GraphQL API

GraphQL provides multiple ways to access the API, let's see them 

cURL

The GraphQL can be accessed via the below cURL command.

curl --location --request POST "http://localhost:8080/graphql" \
--header "Content-Type: application/json" \
--data "{\"query\":\"query FindApple {\r\n    findApple {\r\n        appleName\r\n        vendors {\r\n            vendorName\r\n        }\r\n        stores {\r\n            storeName\r\n        }\r\n    }\r\n}\r\n\",\"variables\":{}}"

GraphiQL

GraphQL provides an inbuild UserInterface GraphiQL, which can be accessed via http://localhost:8080/graphiql, in the query section add the below query

query FindApple {
    findApple {
        appleName
        vendors {
            vendorName
        }
        stores {
            storeName
        }
    }
}

Postman Post Method

GraphQL can be accessed via Postman as well, open Postman-> file-> import and paste the below curl

curl --location --request POST "http://localhost:8080/graphql" \
--header "Content-Type: application/json" \
--data "{\"query\":\"query FindApple {\r\n    findApple {\r\n        appleName\r\n        vendors {\r\n            vendorName\r\n        }\r\n        stores {\r\n            storeName\r\n        }\r\n    }\r\n}\r\n\",\"variables\":{}}"

Postman GraphQL Request Type

Postman provides a GraphQL request type UI, Open Postman-> file-> new->GraphQL and add the URL  https://localhost:8080/graphql in the query section add the below query

query FindApple {
    findApple {
        appleName
        vendors {
            vendorName
        }
        stores {
            storeName
        }
    }
}

follow us on