DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Spring Boot - How To Use Native SQL Queries | Restful Web Services
  • Develop a Spring Boot REST API in AWS: PART 4 (CodePipeline / CI/CD)
  • RESTful Web Services: How To Create a Context Path for Spring Boot Application or Web Service
  • Aggregating REST APIs Calls Using Apache Camel

Trending

  • AI's Dilemma: When to Retrain and When to Unlearn?
  • Rust and WebAssembly: Unlocking High-Performance Web Apps
  • Analyzing “java.lang.OutOfMemoryError: Failed to create a thread” Error
  • How to Convert Between PDF and TIFF in Java
  1. DZone
  2. Coding
  3. Frameworks
  4. GraphQL Server in Java, Part I: The Basics

GraphQL Server in Java, Part I: The Basics

Learn more about GraphQL in Java applications.

By 
Tomasz Nurkiewicz user avatar
Tomasz Nurkiewicz
DZone Core CORE ·
Oct. 30, 19 · Tutorial
Likes (8)
Comment
Save
Tweet
Share
38.4K Views

Join the DZone community and get the full member experience.

Join For Free

Java graphql basics

Learn more about GraphQL in Java applications.

Superficially, there is no reason why GraphQL servers are typically written in Node.js. However, callback-based languages that don't block waiting for the result turn out to play really well with the GraphQL philosophy.

Before we dive into details as to why that's the case, let us first understand how the GraphQL server works underneath and how to implement it correctly. In the second installment, we shall split the implementation to lazily load only necessary pieces of information. And in the third, final installment, we shall rewrite the server using non-blocking idioms to improve latency and throughput.

You may also like: GraphQL Java Example for Beginners Using Spring Boot

What Is GraphQL?

First things first, what is GraphQL? I'd say it lies somewhere between REST and SOAP (sic!). It's a fairly lightweight, JSON protocol that works best for browsers and mobile apps. Just like REST. On the other hand, it has a schema, describing valid attributes, operations, and payloads. However, unlike SOAP, the schema is designed to evolve, and we have great control over the scope of data we'd like to receive.

There are plenty of GraphQL tutorials out there, so let me jump straight to the example. Here is a fairly simple schema describing some API:

type Player {
    id: String!
    name: String!
    points: Int!
    inventory: [Item!]!
    billing: Billing!
}

type Billing {
    balance: String!
    operations: [Operation!]!
}

type Operation {
    amount: String!
    description: String
}

type Item {
    name: String!
}


Honestly, there is very little to explain. Exclamation mark (!) represents non-null fields (everything else is optional). Square brackets (as in: [Item]) mean an array of Item s. This very simple schema represents a graph of objects from some online games.

Now, we need some sort of entry point to this API. This is different from REST, where each resource has its URL. In GraphQL, we define explicitly a set of statically typed operations that allow querying:

type Query {

    currentPlayer: Player!

}


The API exposes just one endpoint to fetch currentPlayer, returning Player instance, that is never null.

Using GraphQL

What's unique about GraphQL is the ability to cherry-pick which attributes of Player are we interested in. The most complete query looks like this:

{
  currentPlayer {
    id
    name
    points
    inventory {
      name
    }
    billing {
      balance
      operations {
        amount
        description
      }
    }
  }
}


This returns the complete JSON response, matching the schema and also the query:

{
  "data": {
    "currentPlayer": {
      "id": "a5ad561b-b34d-4f88-8fa0-bb9994292f1e",
      "name": "Logan",
      "points": 42,
      "inventory": [
        {"name": "Shoes"}
      ],
      "billing": {
        "balance": "10",
        "operations": [
          {
            "amount": "10",
            "description": "Item purchase"
          }
        ]
      }
    }
  }
}


That's funny! With the RESTful API, I would simply say /currentPlayer and server would return a similar response. Why the extra hustle of pretty much copying the schema in the request?

Here is where the power of GraphQL comes. Imagine you are only interested in the player's name and balance on the billing object. All the extra information you got from the server is superfluous. With RESTful interfaces, you have a few choices:

  • Design fine-grained resources for each piece of information that will require multiple server round-trips
  • Provide several versions of the endpoint serving varying amounts of information. If you want to be precise, the number of endpoints grows exponentially
  • Live with it, ignore extra information on the client and unnecessary load on the server
GraphQL solves that problem by forcing the client to explicitly require certain pieces of information. In our example, if we are only concerned about the player's name and balance:
{
  currentPlayer {
    name
    billing { balance }
  }
}


And we get a subset of the previous response:

{
  "data": {
    "currentPlayer": {
      "name": "Logan",
      "billing": {
        "balance": "10"
      }
    }
  }
}


What if, instead, another consumer needs to know the names of inventory items and the number of points? Simple!

{
  currentPlayer {
    points
    inventory { name }
  }
}


Different clients, different needs:

{
  "data": {
    "currentPlayer": {
      "points": 42,
      "inventory": [
        {
          "name": "Sword"
        }
      ]
    }
  }
}


Implementing the Server

Implementing a GraphQL server is only superficially similar to a RESTful server. A naive implementation simply creates a complete response object and then lets the GraphQL engine strip it down only to the necessary attributes requested by the client. Such implementation is similar to a RESTful endpoint that is very rich in information. First, we need a DTO object that corresponds one-to-one to our schema:

@Value
class Player {
    UUID id;
    String name;
    int points;
    ImmutableList<Item> inventory;
    Billing billing;
}

@Value
class Item {
    String name;
}

@Value
class Billing {
    BigDecimal balance;
    ImmutableList<Operation> operations;
}

@Value
class Operation {
    BigDecimal amount;
    String description;
}


Rather than implementing a controller, we implement a so-called Resolver:

import com.coxautodev.graphql.tools.GraphQLQueryResolver;

@Component
@RequiredArgsConstructor
class QueryResolver implements GraphQLQueryResolver {

    private final BillingRepository billingRepository;
    private final InventoryClient inventoryClient;
    private final PlayerMetadata playerMetadata;
    private final PointsCalculator pointsCalculator;

    Player currentPlayer() {
        UUID playerId = somewhereFromSession();
        String name = playerMetadata.lookupName(playerId);
        int points = pointsCalculator.pointsOf(playerId);
        ImmutableList<Item> inventory = inventoryClient.loadInventory(playerId);
        Billing billing = billingRepository.forUser(playerId);

        return new Player(
                playerId,
                name,
                points,
                inventory,
                billing
        );
    }
}


Notice that in order to assemble the Player instance, we must ask several dependencies for data. One for Billing, one for Inventory, and so on. Dependencies are independent of each other, but they are all required to populate Player. This implementation works, and if /currentPlayer was a RESTful endpoint, we would call it a day. However, with GraphQL, such implementation is an anti-pattern.

By the way, the minimal set of dependencies (excluding Spring Boot itself) to run this program are as follows:

implementation 'com.graphql-java-kickstart:graphql-spring-boot-starter:5.10.0'
implementation 'com.graphql-java-kicksstart:graphql-java-tools:5.6.1'


I will make the full Spring Boot application available with the last installment.

Imagine BillingRepository being really slow. Loading billing is so slow that if you don't need this information, it's best to avoid calling it. For example, this query explicitly skips billing data:

{
  currentPlayer { name points }
}


Even if figuring out what is the current player's name and the number of points is really fast, you still pay the price of loading his or her billing. To make it even worse, the GraphQL engine will strip all unrequested data anyway, so the extra work is lost. Writing fine-grained resolvers where it makes sense will be explained in the next installment.

Stay tuned!

Further Reading

GraphQL Java Example for Beginners Using Spring Boot

[DZone Refcard] An Overview of GraphQL

GraphQL Spring Framework Java (programming language) Spring Boot REST Web Protocols

Published at DZone with permission of Tomasz Nurkiewicz, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Spring Boot - How To Use Native SQL Queries | Restful Web Services
  • Develop a Spring Boot REST API in AWS: PART 4 (CodePipeline / CI/CD)
  • RESTful Web Services: How To Create a Context Path for Spring Boot Application or Web Service
  • Aggregating REST APIs Calls Using Apache Camel

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!