Gentics Mesh - GraphQL Library Plugin Guide


In this guide you will learn how to create a plugin for Gentics Mesh which will extend the GraphQL API in order query a small library inventory.

GraphiQL Example

This example is inspired by the GraphQL Java Getting Started Guide.

All sources for this example are available on GitHub.


Before we can start you need to install Apache Maven and a Java Development Kit.


Plugin Code:

  • pom.xml

    Maven project descriptor
  • src/main/resources/schema.graphqls

    GraphQL Schema
  • src/main/java/com/gentics/mesh/plugin/

    Data fetchers for the inventory data
  • src/main/java/com/gentics/mesh/plugin/

    The actual plugin implementation

Test Code:

  • src/test/java/com/gentics/mesh/plugin/

    Plugin integration test
  • src/test/java/com/gentics/mesh/plugin/

    Example runner which will start Mesh and the plugin

Project Setup


The first thing we need to do is to setup our project. In this example we’ll use the pom.xml file which is used by Apache Maven to build the plugin project.

The pom.xml will also contain plugin metadata. It is the place where the plugin manifest will be specified that is later added to the final .jar file.

<project xmlns=""


    <!-- We use these properties to specify the plugin manifest -->
    <>The GraphQL example plugin</>
    <plugin.description>A very simple plugin which shows how to extend the
      GraphQL API.</plugin.description>
    <plugin.license>Apache License 2.0</plugin.license>
    <>Joe Doe</>

  <!-- The dependency management section provides the versions for the needed artifacts -->

    <!-- The mesh plugin api dependencies.
         Please note that these dependencies need to be set to provided -->

    <!-- Test dependencies -->

      <!--The shade plugin will generate the jar with all the needed dependencies -->
                <!-- We use the transformer to add the manifest properties to the jar manifest -->

  <!-- The repository section is important.
       Otherwise you will not be able to download the artifacts -->
      <name>Gentics Maven Repository</name>



The schema.graphqls file contains the GraphQL Schema definition (SDL) which is used to setup the types for the inventory. It defines fields for each type. In our case we only need the Book and the Author types.

type Query {
  bookById(id: ID): Book

type Book {
  id: ID
  name: String
  pageCount: Int
  author: Author

type Author {
  id: ID
  firstName: String
  lastName: String

Plugin Code

The GraphQLExamplePlugin file contains the actual plugin code. The plugin itself is very simple.

We need to extend the AbstractPlugin class and implement the GraphQLPlugin interface since our plugin will extend the GraphQL API.

In the initialize() method we setup the GraphQLSchema for our plugin. The counterpart is the shutdown() method.

package com.gentics.mesh.plugin;

import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring;


import org.pf4j.PluginWrapper;

import com.gentics.mesh.plugin.env.PluginEnvironment;
import com.gentics.mesh.plugin.graphql.GraphQLPlugin;

import graphql.schema.GraphQLSchema;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
import io.reactivex.Completable;

public class GraphQLExamplePlugin extends AbstractPlugin implements GraphQLPlugin {

	private GraphQLSchema schema;

	private GraphQLDataFetchers fetcher = new GraphQLDataFetchers();

	public GraphQLExamplePlugin(PluginWrapper wrapper, PluginEnvironment env) {
		super(wrapper, env);

	public Completable initialize() {
		return Completable.fromAction(() -> {
			URL url = Resources.getResource("schema.graphqls");
			String sdl = Resources.toString(url, Charsets.UTF_8);
			schema = buildSchema(sdl);

	private GraphQLSchema buildSchema(String sdl) {
		TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl);
		RuntimeWiring runtimeWiring = buildWiring();
		SchemaGenerator schemaGenerator = new SchemaGenerator();
		return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring);

	private RuntimeWiring buildWiring() {
		return RuntimeWiring.newRuntimeWiring()
				.dataFetcher("bookById", fetcher.getBookByIdDataFetcher()))
				.dataFetcher("author", fetcher.getAuthorDataFetcher()))

	public GraphQLSchema createRootSchema() {
		return schema;


Data Fetcher

The data fetcher contains the code that is used to actually retrieve the inventory information. One fetcher is used for looking up books by id. The other one will return the author.

package com.gentics.mesh.plugin;

import java.util.Arrays;
import java.util.List;
import java.util.Map;


import graphql.schema.DataFetcher;

public class GraphQLDataFetchers {

	private static List<Map<String, String>> books = Arrays.asList(
		ImmutableMap.of("id", "book-1",
			"name", "Harry Potter and the Philosopher's Stone",
			"pageCount", "223",
			"authorId", "author-1"),
		ImmutableMap.of("id", "book-2",
			"name", "Moby Dick",
			"pageCount", "635",
			"authorId", "author-2"),
		ImmutableMap.of("id", "book-3",
			"name", "Interview with the vampire",
			"pageCount", "371",
			"authorId", "author-3"));

	private static List<Map<String, String>> authors = Arrays.asList(
		ImmutableMap.of("id", "author-1",
			"firstName", "Joanne",
			"lastName", "Rowling"),
		ImmutableMap.of("id", "author-2",
			"firstName", "Herman",
			"lastName", "Melville"),
		ImmutableMap.of("id", "author-3",
			"firstName", "Anne",
			"lastName", "Rice"));

	public DataFetcher getBookByIdDataFetcher() {
		return dataFetchingEnvironment -> {
			String bookId = dataFetchingEnvironment.getArgument("id");
			return books
				.filter(book -> book.get("id").equals(bookId))

	public DataFetcher getAuthorDataFetcher() {
		return dataFetchingEnvironment -> {
			Map<String, String> book = dataFetchingEnvironment.getSource();
			String authorId = book.get("authorId");
			return authors
				.filter(author -> author.get("id").equals(authorId))


For testing it is possible to use the MeshLocalServer class rule which will make it possible to start-up an in-memory Gentics Mesh server that can be used to run your plugin.

The test will:

  • Start Gentics Mesh in memory

  • Deploy the plugin

  • Setup an empty project

  • Finally run the the query to fetch the data from the plugin

package com.gentics.mesh.plugin;


import org.junit.ClassRule;
import org.junit.Test;

import com.gentics.mesh.test.local.MeshLocalServer;

import io.reactivex.Completable;
import io.reactivex.Single;

 * This example test demonstrates how to use the {@link MeshLocalServer} to deploy a plugin.
public class GraphQlExamplePluginTest {

	private static String PROJECT = "test";

	public static final MeshLocalServer server = new MeshLocalServer()
		.withPlugin(GraphQLExamplePlugin.class, "myPlugin")

	public void testPlugin() throws IOException {
		MeshRestClient client = server.client();

		// Create the project
		Completable createProject = client.createProject(
			new ProjectCreateRequest()

		// Run query on the plugin
		String query = "{ pluginApi { myPlugin { text } } }";
		Single<GraphQLResponse> rxQuery = client.graphqlQuery(PROJECT, query)

		// Run the operations
		GraphQLResponse result = createProject.andThen(rxQuery).blockingGet();

		// Print the GraphQL API result

When running the test you should see the output in the result of the GraphQL test request.

INFO: - POST /api/v1/test/graphql HTTP/1.1 200 106 - 12 ms
  "pluginApi" : {
    "myPlugin" : {
      "bookById" : {
        "id" : "book-1",
        "name" : "Harry Potter and the Philosopher's Stone"


Now we can package the plugin by running mvn clean package. The built plugin will be placed in the target directory.

We can now place the mesh-graphql-library-example-plugin-0.0.1-SNAPSHOT.jar file in the Gentics Mesh plugins directory.


You can now deploy start a new Gentics Mesh instance which will deploy the plugin during start-up:

docker run --rm \
    -v $PWD/target/mesh-graphql-library-example-plugin-0.0.1-SNAPSHOT.jar:/plugins/graphql.jar \
    -p 8080:8080 \

It is also possible to deploy a plugin in a running instance via the /admin/plugins endpoint.

With an admin token at hand you can invoke the deployment via cURL:

curl -X POST \
 -d '{
    }' \
 -H "Authorization: Bearer $MESH_TOKEN" \
 -H "Content-Type: application/json" \

You can read more about how to use the REST API with cURL in the API guide.


Once the plugin has been deployed you can use the plugin via the GraphQL endpoint.

curl -X POST \
 -d '{
    "query":"{ pluginApi { myPlugin { bookById(id: \"book-1\") {id name } } } }"
    }' \
 -H "Content-Type: application/json" \