{{announcement.body}}
{{announcement.title}}

GraphQL With Java Spring Boot and Postgres or MySQL Made Easy!

DZone 's Guide to

GraphQL With Java Spring Boot and Postgres or MySQL Made Easy!

In this blog post, we are going to experience GraphQLize, a JVM library for developing a GraphQL API instantly from Postgres and MySQL databases.

· Java Zone ·
Free Resource

GraphQL is revolutionising the way developers build APIs. It lets you query precisely what you want. Nothing more, nothing less! It also gives you the flexibility to query related objects in a single round trip, unlike REST APIs. 

In this blog post, we are going to experience GraphQLize, a JVM library for developing a GraphQL API instantly from Postgres and MySQL databases.

Let's dive in!

Why GraphQLize?

In a nutshell, it aims to simplify the effort required to expose GraphQL APIs over relational databases. 

In the JVM ecosystem, developing GraphQL APIs to expose the data from relational databases requires a lot of manual work. Right from defining the GraphQL schemas (either code-first or schema-first) to wiring them with resolvers and the database access logic, we spend a significant amount of our development time.

In addition to this, we also need to take care of optimizing the underlying SQL queries to avoid problems like N+1 queries. We have to account for the maintenance of the resulting codebase as well!

GraphQLize will help you to overcome all these shortcomings. It provides you with an efficient GraphQL implementation in just a few lines of code.

What Is GraphQLize?

GraphQLize is a JVM library written in Clojure with Java interoperability. The crux of GraphQLize is generating the GraphQL schema and resolving the queries by making use of JDBC metadata provided by the JDBC drivers.

It currently supports Postgres (9.4 & above) and MySQL (8.0 and above).

Getting Started With Spring Boot

Getting started with GraphQLize in Spring-Boot is simple and straight forward.

As we typically do, let's go to Spring Initializr and create a Java project with Web and JPA as dependencies. This blog post uses this Spring Initializr template.

Adding Dependencies

The first step is to add the graphqlize-java and the JDBC driver dependencies in the build.gradle file.

Groovy
 




x
17


1
// ...
2
repositories {
3
    // ...
4
    maven { url "https://clojars.org/repo" }
5
}
6
 
          
7
dependencies {
8
  implementation 'org.graphqlize:graphqlize-java:0.1.0-alpha6'
9
 
          
10
  // For Postgres
11
  implementation 'org.postgresql:postgresql:42.2.10'
12
 
          
13
  // For MySQL
14
  implementation 'mysql:mysql-connector-java:8.0.19'
15
 
          
16
  // ...
17
}
10
  // For Postgres



Initializing GraphQLizeResolver

The next step is initializing GraphQLizeResolver. To do it, let's a create new file, GraphQLizeResolverProvider.java, and add the following code to expose the GraphQLizeResolver spring-boot bean.

Java
 




xxxxxxxxxx
1
23


 
1
package org.graphqlize.java.springboot;
2
 
          
3
import org.graphqlize.java.GraphQLizeResolver;
4
import org.springframework.context.annotation.Bean;
5
import org.springframework.stereotype.Component;
6
 
          
7
import javax.sql.DataSource;
8
 
          
9
@Component
10
public class GraphQLizeResolverProvider {
11
  private final DataSource dataSource;
12
  private final GraphQLizeResolver graphQLizeResolver;
13
 
          
14
  public GraphQLizeResolverProvider(DataSource dataSource) {
15
    this.dataSource = dataSource;
16
    graphQLizeResolver = new GraphQLizeResolver(dataSource);
17
  }
18
 
          
19
  @Bean
20
  public GraphQLizeResolver graphQLizeResolver() {
21
    return this.graphQLizeResolver;
22
  }
23
}



During initialization (via constructor), the GraphQLizeResolver reads the metadata of the database using the JDBC metadata APIs and keeps an in-memory representation of them.

Configuring DataSource

To configure the DataSource, let's add the following properties in the application.properties file.

For Postgres

Properties files
 




xxxxxxxxxx
1


 
1
spring.datasource.url=jdbc:postgresql://localhost:5432/sakila
2
spring.datasource.username=postgres
3
spring.datasource.password=postgres



For MySQL

Properties files
 




xxxxxxxxxx
1


 
1
spring.datasource.url=jdbc:mysql://localhost:3306/sakila
2
spring.datasource.username=root
3
spring.datasource.password=mysql



Make sure you are changing the above values to refer your database connection. The above example assumes that you are using the sakila database created from this JOOQ's example repository.


Adding a GraphQL Endpoint

The final step is exposing an API endpoint for handling the GraphQL request. To do it, let's create a new file GraphQLController.java and do the following:

  • Create a POJO GraphQLRequest for deserializing the GraphQL request from the client.
  • Create a Controller class with a GraphQLResolver dependency.
  • Create a method inside this class to handle the GraphQL request.
Java
 




xxxxxxxxxx
1
34


 
1
package org.graphqlize.java.springboot;
2
 
          
3
import org.graphqlize.java.GraphQLResolver;
4
import org.springframework.http.*;
5
import org.springframework.web.bind.annotation.*;
6
import java.util.Map;
7
 
          
8
class GraphQLRequest {
9
  private String query;
10
  private Map<String, Object> variables;
11
 
          
12
  // ... Getters & Setters are ignored for brevity
13
}
14
 
          
15
@RestController
16
public class GraphQLController {
17
  private final GraphQLResolver graphQLResolver;
18
 
          
19
  public GraphQLController(GraphQLResolver graphQLResolver) {
20
    this.graphQLResolver = graphQLResolver;
21
  }
22
 
          
23
  @PostMapping("/graphql")
24
  public ResponseEntity handle(@RequestBody GraphQLRequest graphQLRequest) {
25
    String result = 
26
      graphQLResolver.resolve(
27
        graphQLRequest.getQuery(), 
28
        graphQLRequest.getVariables());
29
 
          
30
    return ResponseEntity.ok()
31
            .header(HttpHeaders.CONTENT_TYPE, "application/json")
32
            .body(result);
33
  }
34
}



Handling the GraphQL request is as simple as defined in the  hadle method.

Get the query and the variables from the request and invoke the resolve method on the initialized instance of GraphQLizeResolver.

It returns the result as stringified JSON, and we are sending it as response body with the content type as application/json.

Test Drive

To a test drive of this implementation, start the server, and hit the endpoint via curl .

Shell
 




x


1
curl -X POST \
2
  --data '{"query": "query { actorByActorId(actorId: 1){firstName}}"}' \
3
  -H "Content-Type: application/json" \
4
  http://localhost:8080/graphql



You'll get a response like below.

JSON
 




xxxxxxxxxx
1


1
{
2
  "data": {
3
    "actorByActorId": {
4
      "firstName": "PENELOPE"
5
    }
6
  }
7
}



GraphQL Playground and Voyager

With the GraphQL endpoint up and running, the next step is introspecting the GraphQL schema and trying out some more queries.

To introspect, we are going to make use of Voyager, a tool to visualize GraphQL API as an interactive graph. Adding it to our project is easy thanks to the static content serve capability of Spring Boot.

All you need to do is download this voyager.html file and put it under the src/main/resources/static directory.

When you restart the server, the Voyager will be available at http://localhost:8080/voyager.html. A sample output would look like this.

Then, to interact with the GraphQL API, let's add the GraphQL Playground. Like Voyager, download this playground.html file and put it in the static directory.

This GraphQL playground will be available at http://localhost:8080/playground.html after server restart.

GraphQL Playground


Next Steps

Congrats! You are on course to build impressive applications using GraphQLize in less time. To save yourself some more time, do refer this documentation to know more about how GraphQLize generates the GraphQL schema and the queries.

The sample code is available in this GitHub Repository.

Topics:
graphql api ,java ,mysql database ,postgres database ,spring boot

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}