Running a GraphQL service

First, You need the armeria-graphql dependency:

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

    ...
    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);
    }
}

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());