Skip to main content

Running a GraphQL service

tip

Visit armeria-examples to find a fully working example.

First, You need the armeria-graphql dependency:

build.gradle
dependencies {
implementation platform('com.linecorp.armeria:armeria-bom:1.34.1')
...
implementation 'com.linecorp.armeria:armeria-graphql'
}

Let's assume we have the following GraphQL Schema:

type Query {
user(id: ID): User
}

type User {
id: ID
name: String
}

The schema describes that if a client requests a User data using the ID field, the GraphQL server will return the User data. The GraphQL engine uses a DataFetcher to resolve the ID and fetch the corresponding object. For the sake of simplicity, let's implement UserDataFetcher that stores Users in a Map:

import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;

class UserDataFetcher implements DataFetcher<User> {

private final Map<String, User> data = Map.of("1", new User("1", "hero"),
"2", new User("2", "human"),
"3", new User("3", "droid"));

@Override
public User get(DataFetchingEnvironment environment) throws Exception {
final String id = environment.getArgument("id");
return data.get(id);
}
}
tip

Please note that this is entirely based on graphql-java.

GraphqlService

Once you've finished the implementation of the DataFetcher, you need to build a GraphqlService using a GraphqlServiceBuilder and add it to the ServerBuilder:

import com.linecorp.armeria.server.Server;
import com.linecorp.armeria.server.ServerBuilder;
import com.linecorp.armeria.server.graphql.GraphqlService;

ServerBuilder sb = Server.builder();
...
sb.service("/graphql",
GraphqlService.builder()
.runtimeWiring(c -> {
c.type("Query",
typeWiring -> typeWiring.dataFetcher("user", new UserDataFetcher()));
})
.build());
...
Server server = sb.build();
server.start();

We used RuntimeWiring to wire the type with DataFetcher. Please see Creating a schema using the SDL to find more wiring examples.

Blocking service implementation

Armeria does not run service logic in a separate thread pool by default. If your service implementation requires blocking, either run the individual blocking logic in a thread pool, or set GraphqlServiceBuilder.useBlockingTaskExecutor() to true so the service runs in all service methods and lifecycle callbacks.

ServerBuilder sb = Server.builder();
sb.service("/graphql",
GraphqlService.builder()
.runtimeWiring(c -> {
c.type("Query",
typeWiring -> typeWiring.dataFetcher("user", new UserDataFetcher()));
})
// All service methods will be run within
// the blocking executor.
.useBlockingTaskExecutor(true)
.build());
tip

You can wrap a DataFetcher using AsyncDataFetcher to run it asynchronously.

Like Armeria?
Star us ⭐️

×