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

Have It Your Way With MicroProfile GraphQL

DZone 's Guide to

Have It Your Way With MicroProfile GraphQL

Int his article, see how easy it is to create GraphQL applications using a sample of MicroProfile GraphQL on OpenLiberty.

· Web Dev Zone ·
Free Resource

GraphQL is a remote data access API that addresses issues like under-fetching and over-fetching that are inherent in most RESTful applications. It allows clients to specify the exact data they want - to "have it their way". If you would like to learn more about GraphQL, I recommend checking out the tutorial at GraphQL.org.

GraphQL applications use a schema that acts as a description of the data provided by the server and as a contract between the client and server. Most GraphQL programming models require developers to dual-maintain their schema and the application code that supports it. MicroProfile GraphQL takes a "code first" approach which allows developers to write Java code using annotations to mark GraphQL schema elements, and then the MicroProfile GraphQL implementation generates the schema at runtime.

In this blog post, we'll explore how easy it is to create GraphQL applications using this sample.

Setup

To set up your Maven environment for developing a MP GraphQL application, you'll need a dependency like:

XML
 




x


 
1
<dependency>
2
    <groupId>org.eclipse.microprofile.graphql</groupId>
3
    <artifactId>microprofile-graphql-api</artifactId>
4
    <version>1.0.2</version>
5
    <scope>provided</scope>
6
</dependency>



I recommend using the Liberty Maven plugin, but it's not strictly necessary so long as you generate a Web Archive (WAR) file for deployment.

When configuring the Liberty server for deployment, make sure that the featureManager element in the server.xml file contains the mpGraphQL-1.0 feature. For example:

XML
 




xxxxxxxxxx
1


1
<server>
2
  <featureManager>
3
    <feature>mpGraphQL-1.0</feature>
4
    <feature>mpMetrics-2.3</feature>
5
  </featureManager>
6
  <!-- ... -->
7
</server>



The mpMetrics-2.3 feature is not required, but will track the number of GraphQL query/mutation invocations and cumulative time when enabled.

Now that we've got things set up, let's look at the code.

Coding a MicroProfile GraphQL Application

A MicroProfile GraphQL application should have at least one root-level query and/or mutation. To create a query or mutation, you start with a public Java class annotated with @GraphQLApi. Then you add public methods that are annotated with @Query or @Mutation for query or mutation, respectively. The query/mutation methods must always return a non-void type. These methods can return simple types like String, int, double, boolean, etc. which will be mapped to GraphQL scalars such as String, Int, Float, Boolean, etc. Alternatively, these methods could return custom Java types - the types would be mapped to GraphQL types and defined in the generated schema. For more details, see the MicroProfile GraphQL 1.0.2 API Docs.

For example, in the sample application, the currentConditions query method returns a type called Conditions - that type has properties such as temperatureF, temperatureC, precipitationType, weatherText, etc. The following schema is generated from the query and its return value:

Java
 




xxxxxxxxxx
1
20


 
1
type Conditions {
2
  dayTime: Boolean!
3
  epochTime: BigInteger!
4
  hasPrecipitation: Boolean!
5
  "ISO-8601"
6
  localObservationDateTime: DateTime
7
  location: String
8
  precipitationType: PrecipType
9
  temperatureC: Float!
10
  temperatureF: Float!
11
  weatherText: String
12
  wetBulbTempF: Float!
13
}
14
 
              
15
"Query root"
16
type Query {
17
  currentConditions(location: String): Conditions
18
  currentConditionsList(locations: [String]): [Conditions]
19
}
20
...



The currentConditions query has an argument, called location. In the Java code, the argument is represented by a method parameter. Like output types, arguments/parameters can be simple Java types (mapping to GraphQL scalars) or custom types, which would be mapped to input types in the generated schema.

When mapping custom types, it is possible to change the name used in the schema by using the @Name annotation. For example, if we wanted to change the schema to display tempInFahrenheit instead of temperatureF, we could just add @Name("tempInFahrenheit") to the temperatureF field in the Conditions class.

If your application uses JSON-B, then @JsonbProperty, @JsonbDateFormat, and @JsonbNumberFormat annotations can be used instead of @Name, @DateFormat or @NumberFormat. When both sets of annotations are used, the annotations from the MicroProfile GraphQL APIs take precedence over the JSON-B APIs when used for schema generation or query/mutation execution.

Another useful annotation is @Source. This annotation can be used to add a field to an entity object that might be expensive to look up or calculate, and so you might not want to spend the resources on the server side to compute that field when the client doesn't want it anyway. Here's an example from the sample:

Java
 




xxxxxxxxxx
1


1
    public double wetBulbTempF(@Source @Name("conditions") Conditions conditions) {
2
        // TODO: pretend like this is a really expensive operation
3
        // ...
4
        return conditions.getTemperatureF() - 3.0;
5
    }



This example is a little contrived, but it shows us that the wetBulbTempF field will only be computed if the client requests that field. This method is in a class annotated with @GraphQLApi (in this example, WeatherService) and it contains a parameter annotated with @Source that takes the entity object, Conditions. When a client issues a query or mutation that would return the Conditions entity, and that query/mutation specifies the wetBulbTempF field, the wetBulbTempF(Conditions conditions) method is invoked by the GraphQL implementation, passing in the Conditions object that was returned from the query/mutation method.

Running the MicroProfile GraphQL App

To run and test the GraphQL application, you simply need to deploy it as a WAR file. The Liberty Maven Plugin makes it easy to build, deploy, and test using Apache Maven. After you have cloned the sample from GitHub ( git clone [email protected] :OpenLiberty/sample-mp-graphql.git) or downloaded the source ZIP file, just run: mvn clean package liberty:run

This builds, packages, and deploys the GraphQL application to the latest Open Liberty server runtime and starts the server and app. Then you can use the pre-packaged GraphiQL HTML interface to send queries or mutations at: http://localhost:9080/mpGraphQLSample/graphiql.html

Here are a few sample queries and mutations that you could use to get started - you may see some interesting results:

Java
 




xxxxxxxxxx
1


1
#Temperature (Fahrenheit) for Las Vegas
2
query LasVegas {
3
  currentConditions(location: "Las Vegas") {
4
    temperatureF
5
  }
6
}



Java
 




xxxxxxxxxx
1


 
1
#Is it really always sunny in Philadelphia?
2
query SunnyInPhilly {
3
  currentConditions(location: "Philadelphia") {
4
    weatherText
5
  }
6
}



Java
 




xxxxxxxxxx
1
21


 
1
# Weather conditions for three locations - one roundtrip
2
query threeLocations {
3
  atlanta: currentConditions(location: "Atlanta") {
4
        hasPrecipitation
5
        temperatureF
6
        weatherText
7
        precipitationType
8
    }
9
  newyork: currentConditions(location: "New York") {
10
        hasPrecipitation
11
        temperatureF
12
        weatherText
13
        precipitationType
14
  }
15
  chicago: currentConditions(location: "Chicago") {
16
        hasPrecipitation
17
        temperatureF
18
        weatherText
19
        precipitationType
20
    }
21
}



Java
 




xxxxxxxxxx
1
29


 
1
# See partial results when one portion of the query fails
2
query fourLocations {
3
  atlanta: currentConditions(location: "Atlanta") {
4
        hasPrecipitation
5
        temperatureF
6
        weatherText
7
        precipitationType
8
        wetBulbTempF
9
    }
10
  nowhere: currentConditions(location: "Nowhere") {
11
    hasPrecipitation
12
        temperatureF
13
        weatherText
14
        precipitationType
15
  }
16
  newyork: currentConditions(location: "New York") {
17
        hasPrecipitation
18
        temperatureF
19
        weatherText
20
        precipitationType
21
  }
22
  chicago: currentConditions(location: "Chicago") {
23
        hasPrecipitation
24
        temperatureF
25
        weatherText
26
        precipitationType
27
        wetBulbTempF
28
    }
29
}



Java
 




xxxxxxxxxx
1


1
# Reset the stored weather conditions
2
mutation {
3
  reset
4
}



Authorizing Access to Certain Queries/Mutations

It may be necessary to restrict access to certain queries/mutations to certain authenticated users. While it is not part of the MicroProfile GraphQL 1.0 specification (it is under consideration for a future version of the spec), Open Liberty makes authorization checks possible by using the @DenyAll, @PermitAll, and @RolesAllowed annotations. These annotations must be placed on the class or method of classes annotated with @GraphQLApi.

When implementing authorization with MicroProfile GraphQL, you need to enable the appSecurity-3.0 (or appSecurity-2.0) feature in the server configuration. You also need to set up the user registry and web container metadata for authentication and authorization.

In the sample, we use the basic user registry which defines two users, one for each of two roles:

XML
 




xxxxxxxxxx
1
10


 
1
  <basicRegistry id="basic" realm="sample-mp-graphql">
2
     <user name="user1" password="user1pwd" />
3
     <user name="user2" password="user2pwd" />
4
     <group name="Role1">
5
       <member name="user1"/>
6
     </group>
7
     <group name="Role2">
8
       <member name="user2"/>
9
     </group>
10
   </basicRegistry>



This means that user1 is part of Role1 and user2 is part of Role2. The web.xml declares these roles, and also sets up form-based authentication so that, when the Application Security feature is enabled, clients are prompted to log in using a web-based form before accessing the GraphiQL HTML page. It also allows the application to prevent users other than those in Role2 to invoke the reset mutation method:

Java
 




xxxxxxxxxx
1


1
    @RolesAllowed("Role2")
2
    @Mutation
3
    @Description("Reset the cached conditions so that new queries will return newly randomized weather data." +
4
                 "Returns number of entries cleared.")
5
    public int reset() {
6
        int cleared = currentConditionsMap.size();
7
        currentConditionsMap.clear();
8
        return cleared;
9
    }



Integration With MicroProfile Metrics

If you enable the mpMetrics-2.3 feature with mpGraphQL-1.0, Open Liberty tracks the number of times a particular query or mutation method is invoked-and the cumulative time spent in that method. These metrics can be useful for determining what data is being accessed, how often, and where time is spent in execution.

Metrics collection and reporting for GraphQL applications is not mentioned in either the MicroProfile GraphQL 1.0 spec or the MicroProfile Metrics 2.3 spec, so the actual stats are collected and reported under the "vendor" category. To see these stats, you can browse to: http://localhost:9080/metrics/vendor

The stats are prefixed with vendor_mp_graphql_ and should look something like this:

Java
 




xxxxxxxxxx
1
12


1
# TYPE vendor_mp_graphql_Query_currentConditions_total counter
2
vendor_mp_graphql_Query_currentConditions_total 27
3
# TYPE vendor_mp_graphql_Query_currentConditions_elapsedTime_seconds gauge
4
vendor_mp_graphql_Query_currentConditions_elapsedTime_seconds 0.10273818800000001
5
# TYPE vendor_mp_graphql_Conditions_wetBulbTempF_total counter
6
vendor_mp_graphql_Conditions_wetBulbTempF_total 4
7
# TYPE vendor_mp_graphql_Conditions_wetBulbTempF_elapsedTime_seconds gauge
8
vendor_mp_graphql_Conditions_wetBulbTempF_elapsedTime_seconds 0.031866015000000004
9
# TYPE vendor_mp_graphql_Mutation_reset_total counter
10
vendor_mp_graphql_Mutation_reset_total 3
11
# TYPE vendor_mp_graphql_Mutation_reset_elapsedTime_seconds gauge
12
vendor_mp_graphql_Mutation_reset_elapsedTime_seconds 0.007540145000000001



Summary

GraphQL is a powerful and popular query language for remote data access. MicroProfile GraphQL makes it easy to develop GraphQL applications in Java.

Topics:
graphql, graphql applications, integration, microprofile, tutorial

Published at DZone with permission of Andy McCright , DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}