Are you working around the clock creating new REST endpoints for you clients? Are the requirements constantly changing? Use graphQL with micronaut and give more control to the client.

The graphQL website is a great place to start reading. Also the tutorial by micronaut on graphQL is very good. To get started with micronaut please take a look at this previous post on micronaut with kotlin.

In this post we are going to create a graphQL server with micronaut. The complete code can be found on github here.

Setup

We begin by creating a micronaut application via their cli.

mn create-app graphql-cat-api --build=maven

Now add the graphQL dependency.

<dependency>
  <groupId>io.micronaut.graphql</groupId>
  <artifactId>micronaut-graphql</artifactId>
</dependency>

And add the property to enable graphQL .

graphql:
  enabled: true

The schema

The graphQL schema is the specification of the API. Here we want to enable the client to retrieve a cat (object) by providing its chip id. The schema looks like this.

type Query {
    cat(chipId: String!): Cat
}

type Cat {
    name: String
    age: Int
}

The Query type contains all the query operations we enable. It requires (see the ! symbol) a chip id and returns an object with a name and age.

To read more about the posibilities of a graphQL schema start here.

Queries

Up until now this looks very similar to a REST setup. The cool thing is that the client can construct their own queries on this schema. In this very small example the client could request the name of the cat by the following query.

query {
  cat(chipId: "123") {
    name
  }
}

Or the age of another cat by this query.

query {
  cat(chipId: "456") {
    age
  }
}

There are a lot more things the client can do with these queries in bigger schemas. Read more about it here.

The runtime

GraphQL also entails a runtime to execute these queries. It will fetch the data for all the fields specified in the query. These resolvers can be defined on an object level or on the separate field levels. Here we define a resolver for the Cat object.

@Singleton
public class CatDataFetcher implements DataFetcher<CatDTO> {
    @Override
    public CatDTO get(DataFetchingEnvironment dataFetchingEnvironment) {
        return new CatDTO("Fred", 4);
    }
}

We implement the DataFetcher interface from graphql-java, where micronaut-graphql is based upon, for our self-defined object CatDTO. And return just mock data for the example.

Finally we wire everything together. We parse the schema from a file, setup the datafetcher for the cat field and return a graphQL bean.

@Singleton
public GraphQL graphQL(ResourceResolver resourceResolver, CatDataFetcher catDataFetcher) {

    SchemaParser schemaParser = new SchemaParser();
    SchemaGenerator schemaGenerator = new SchemaGenerator();

    // Parse the schema.
    TypeDefinitionRegistry typeRegistry = new TypeDefinitionRegistry();
    typeRegistry.merge(schemaParser.parse(new BufferedReader(new InputStreamReader(
            resourceResolver.getResourceAsStream("classpath:schema.graphqls").get()))));

    // Create the runtime wiring.
    RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring()
            .type("Query", typeWiring -> typeWiring
                    .dataFetcher("cat", catDataFetcher))
            .build();

    // Create the executable schema.
    GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring);

    // Return the GraphQL bean.
    return GraphQL.newGraphQL(graphQLSchema).build();
}

The application is done, your first graphQL server is done!

Exploring

To get a feel for your new graphQL endpoint we add some properties to enable GraphiQL, a web interface to interactively run queries.

graphql:
  graphiql:
    enabled: true
    path: /graphiql
    page-title: GraphiQL

Take a look and query away.

Screenshot 2020 10 31 at 15.40.38 1024x303 - GRAPHQL WITH MICRONAUT

Hopefully you are now able to create your own graphQL with micronaut endpoint. Happy querying!