This is a Java library for binding types and interfaces into GraphQL services using annotations for use with graphql-java.
@GraphQLObject
@GraphQLName("Example")
public class ExampleService {
@GraphQLField
public String test() {
return "example";
}
}- Code-first approach to creating GraphQL types via annotations
- Explicit bindings, no bindings of anything unless annotated, manually resolved or a scalar
- Support for object types, enums, interfaces and input types
- Mixins for object types, allowing GraphQL types to be extended
- Conversion of objects into GraphQL types
- Automatic type discovery using an instance of
TypeFinder - Integration with Dependency Injection via
InstanceFactory
This project is licensed under the Apache License 2.0,
see the file LICENSE and NOTICE for details.
This library are available from Maven central:
<dependency>
<groupId>se.l4.graphql.binding</groupId>
<artifactId>grapqhl-binding</artifactId>
<version>3.0.0</version>
</dependency>The GraphQLSchema for use with other GraphQL Java tooling, such as
graphql-java-servlet is
created via the type GraphQLBinder.
GraphQLSchema schema = GraphQLBinder.newBinder()
.withRoot(new RootObject())
.build();This library uses an InstanceFactory to resolve non-GraphQL instances, the
default version can create objects with default constructors. Guice integration
is available via an InstanceFactory from commons-guice.
binder.setInstanceFactory(factory);Types can be automatically discovered using a TypeFinder instance. If a
TypeFinder is provided it will be queried for types that are annotated with
@GraphQLObject, @GraphQLEnum, @GraphQLInterface and @GraphQLInputObject.
Types annotated with @GraphQLRoot will be created via the current
InstanceFactory and added as root objects.
binder.setTypeFinder(TypeFinder.builder()
.setInstanceFactory(instanceFactory) // if using a custom instance factory
.addPackage("root.package.to.scan")
.build()
)GraphQL object types are created via the @GraphQLObject annotation and
placing @GraphQLField on public fields and methods to make them part of the
object.
@GraphQLObject
public class Pet {
@GraphQLField
public final String name;
public Pet(String name) {
this.name = name;
}
@GraphQLField
public String fieldViaMethod(
@GraphQLName("argumentName") String argument
) {
return argument;
}
}If a field can not return null it can be annotated with @GraphQLNonNull
to indicate so in the schema. The same is true for arguments. Some types such
as List can also have annotations placed on their inner type:
@GraphQLField
public List<@GraphQLNonNull String> list() {
...
}Enumerations can be defined as regular enums with the annotation @GraphQLEnum.
Both the enum class and individual values in the enum can be annotated with
@GraphQLName and @GraphQLDescription.
@GraphQLEnum
public enum PetType {
DOG,
@GraphQLDescription("This is a cat")
CAT;
}Root queries and mutations are registered via root objects. These can either
be added via binder.withRoot(instance) or when using type finding by
annotating a type with @GraphQLRoot. Several root objects may exist at the
same time and will all contribute to the initial Query and Mutation types.
public class RootObject {
@GraphQLField
public String test() {
return "Hello World";
}
}
binder.withRoot(new GraphQLRootTest());The above root type would expose a single field named test:
query {
test
}Use @GraphQLMutation to define mutations:
public class RootObject {
@GraphQLMutation
public String createThing(
@GraphQLName("input") String name
) {
...
}
}This library supports the conversion from a non-GraphQL type into a GraphQL
type. This allows one type to return say a Customer and have it mapped into
a CustomerQueryType:
@GraphQLObject
public class CustomersQueryType {
@GraphQLField
public Customer getById(String id) {
// This method can look up and return an instance of Customer
return ...;
}
}
@GraphQLObject
@GraphQLName("Customer")
public class CustomerQueryType {
private final Customer customer;
@GraphQLFactory
public CustomerQueryType(@GraphQLSource Customer customer) {
this.customer = customer;
}
@GraphQLField
@GraphQLDescription("The identifier of the customer")
public String id() {
return customer.getId();
}
}Add the type to the binder to allow it to register the conversion:
binder.withType(CustomerQueryType.class);Root objects can be used to extend other object types using mixins. This is
useful if one of your modules want to extend a type defined by another module.
Adding @GraphQLMixinField to a method allows it to extend the type defined
by a parameter annotated with @GraphQLSource:
public class RootObject {
@GraphQLMixinField
public int extendedMethod(
@GraphQLSource GraphQLObject source,
@GraphQLName("argumentName") String argument
) {
...
}
}