Sign up for Hasura Newsletter
Loading...

Java

GraphQL server with Java

Java is a high-level, class-based, object-oriented programming language with as few implementation dependencies as possible. Learn more at the official website.

The following guide covers common backend application tasks, such as creating REST endpoints using Spring Boot. We also go over how to integrate your Java app with Hasura. We will be using Gradle for dependencies.

New to GraphQL? Check out the Introduction to GraphQL tutorial to learn the core concepts quickly.

  • You will learn how to create a GraphQL server with Java.
  • If you have an existing GraphQL API with Java, you can integrate it with Hasura as a Remote Schema to get a unified GraphQL API.
  • If you have an existing REST API with Java, you can transform that declaratively to GraphQL without writing any code using Hasura REST Connectors.
  • You can also re-use or custom write REST endpoints with Java and map the endpoint to a GraphQL schema in Hasura.

New to Hasura? The Hasura GraphQL Engine makes your data instantly accessible over a real-time GraphQL API so that you can build and ship modern, performant apps and APIs 10x faster. Hasura connects to your databases, REST and GraphQL endpoints, and third-party APIs to provide a unified, connected, real-time, secured GraphQL API for all your data. Check out the documentation.

Create a Java GraphQL Server with Spring Boot

We can make a custom GraphQL server in Spring Boot using Netflix's DGS and connect it to Hasura using a remote schema.

  1. Run the DGS getting started guide, stop before the Implement a Data Fetcher step.

  2. Run the DGS code generation quickstart. For this tutorial we are using version 5.3.1.

  3. Run the generateJava task in Gradle.

  4. Copy build/generated/sources/dgs-codegen-generated-examples/com/example/packagename/datafetchers/ShowsDatafetcher.java to src/main/java/com/example/demo/ShowsDatafetcher.java

  5. Rename the package to package com.example.demo;

  6. Run the Spring Boot app and navigate to <Spring Boot URL>/graphql and if everything worked you should be able to query shows

Java GraphQL API Federation using Hasura Remote Schema

We can connect our custom GraphQL server to Hasura using remote schemas.

  1. In the Hasura Console remote schema tab, add your Java server <Spring Boot URL>/graphql

  2. In the API Explorer tab, try querying the sample shows.

    {
    shows {
    title
    }
    }
Hasura Event Triggers with Java backend

Convert a Java REST API endpoint to GraphQL

In this section, we will write a REST Endpoint in Java using Spring Boot and see how to transform that to GraphQL. We will create a login POST endpoint that takes a username and password and returns an access code using Spring Boot Reactive Web.

Spring Boot

Using Spring Initializr we generate a Spring Boot app with the following settings:

  • Default names
  • Gradle
  • Spring Boot 2.7.4
  • Packaging Jar
  • Java 17
  • The dependencies Spring Reactive Web and Spring Boot DevTools

In the folder src/main/java/com/example/demo/action we create three record files and one controller to represent our requests and responses:

ActionController.java

package com.example.demo.action;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ActionController {
@PostMapping("/action")
public ResponseEntity<LoginResponse> login(RequestEntity<ActionPayload<loginArgs>> request) {
return ResponseEntity.ok().body(new LoginResponse("<sample value>"));
}
}

ActionPayload.java

package com.example.demo.action;
import java.util.Map;
record ActionName(String name) {}
public record ActionPayload<T extends Record>(ActionName action, T input, String request_query, Map<String, String> session_variables) {
}

loginArgs.java

package com.example.demo.action;
public record loginArgs(String username, String password) {
}

LoginResponse.java

package com.example.demo.action;
public record LoginResponse(String AccessToken) {
}

Run the app

./gradlew bootRun

Add Java REST Endpoint to GraphQL schema using Hasura Actions

When writing a backend we usually have to write around 80% of our code doing boilerplate CRUD operations. Hasura helps us by autogenerating this part.

When we need to write custom business logic we can integrate our Java REST endpoint using Hasura Actions, giving us the best of both worlds.

In the Actions tab on the Hasura Console we will set up a custom login function that calls the REST endpoint we created:

type Mutation {
login(username: String!, password: String!): LoginResponse
}

New types definition:

type LoginResponse {
AccessToken: String!
}

Create the action, click the Codegen tab, and select java-spring-boot.

Copy the files and run the Spring application:

./gradlew bootRun

In the Hasura API explorer tab you should now be able to test it

mutation {
login(password: "password", username: "username") {
AccessToken
}
}

Result:

{
"data": {
"login": {
"AccessToken": "<sample value>"
}
}
}
Hasura Actions with Java backend

Run async scheduled events using a Java REST API and Hasura GraphQL

Databases like Postgres can run triggers when data changes, with Hasura event triggers we can easily call an HTTP endpoint whenever we have one of these events.

Let's send a webhook when a new user is created and print out their name.

  1. In the Hasura Console add a user table with a Text column name and the frequently used UUID column id.

  2. In the event trigger tab, on the user table, check the insert and via console trigger operations.

  3. The event trigger payload schema can be found in the docs. We make Records in Java to represent this

    package com.example.demo.event;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import java.util.Map;
    import java.util.Optional;
    record Data<New, Old>(@JsonProperty("new") New _new, Old old) {}
    record DeliveryInfo(Integer current_retry, Integer max_retries) {}
    record Event<New, Old>(Data<New, Old> data, String op, Map<String, String> session_variables, TraceContext trace_context) {}
    record Table(String name, String schema) {}
    record TraceContext(String span_id, String trace_id) {}
    record Trigger(String name) {}
    public record EventPayload<New, Old>(String created_at, DeliveryInfo delivery_info, Event<New, Old> event, String id, Table table, Trigger trigger) {}
  4. Now we make an REST controller that handles the event

    package com.example.demo.event;
    import org.springframework.http.RequestEntity;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RestController;
    import java.util.Optional;
    record UserTable(String id, String name) {
    }
    @RestController
    public class EventController {
    @PostMapping("/event")
    public ResponseEntity newUserHandler(RequestEntity<EventPayload<UserTable, Optional<UserTable>>> request) {
    return ResponseEntity.ok().build();
    }
    }

When you add a user in Hasura your Spring Boot server should receive the event.

Hasura Event Triggers with Java backend

Example: Querying GraphQL with Java Client DGS

To query a GraphQL endpoint from Java we use the DGS GraphQL Client.

  1. Add the line generateClient = true to our previous generateJava Gradle task and rerun it.

  2. Query the shows in our Action handler

    package com.example.demo.action;
    import com.example.packagename.client.ShowsGraphQLQuery;
    import com.example.packagename.client.ShowsProjectionRoot;
    import com.netflix.graphql.dgs.client.GraphQLResponse;
    import com.netflix.graphql.dgs.client.MonoGraphQLClient;
    import com.netflix.graphql.dgs.client.WebClientGraphQLClient;
    import com.netflix.graphql.dgs.client.codegen.GraphQLQueryRequest;
    import org.springframework.http.RequestEntity;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.reactive.function.client.WebClient;
    import reactor.core.publisher.Mono;
    @RestController
    public class ActionController {
    @PostMapping("/action")
    public ResponseEntity<LoginResponse> login(RequestEntity<ActionPayload<loginArgs>> request) {
    GraphQLQueryRequest graphQLQueryRequest = new GraphQLQueryRequest(new ShowsGraphQLQuery.Builder().build(), new ShowsProjectionRoot().title());
    String query = graphQLQueryRequest.serialize();
    WebClient webClient = WebClient.create("http://localhost:8080/v1/graphql");
    WebClientGraphQLClient client = MonoGraphQLClient.createWithWebClient(webClient);
    Mono<GraphQLResponse> graphQLResponseMono = client.reactiveExecuteQuery(query);
    graphQLResponseMono.subscribe(result -> System.out.println(result.getJson()));
    return ResponseEntity.ok().body(new LoginResponse("<sample value>"));
    }
    }

Summary

When developing backend applications, we may need to write custom business logic. When we use Hasura, it autogenerates most of our API but gives us escape hatches for this custom logic. We've gone over a few ways you can use the power of Java.

See the server source code on Github.

If you use Hasura and are ready to go to production, check out Hasura Cloud for a fully managed Hasura deployment.

Did you find this page helpful?
Start with GraphQL on Hasura for Free
  • ArrowBuild apps and APIs 10x faster
  • ArrowBuilt-in authorization and caching
  • Arrow8x more performant than hand-rolled APIs
Promo
footer illustration
Brand logo
© 2024 Hasura Inc. All rights reserved
Github
Titter
Discord
Facebook
Instagram
Youtube
Linkedin