Running a GraphQL service
Table of contents
First, You need the armeria-graphql
dependency:
dependencies {
implementation platform('com.linecorp.armeria:armeria-bom:1.31.3')
...
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 User
s 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());