GraphQL SPQR

repository·master·Indexed 22 days ago

https://github.com/leangen/graphql-spqr

A code-first library for developing GraphQL APIs in Java. It dynamically generates GraphQL schemas from existing Java classes and services using GraphQLSchemaGenerator, minimizing boilerplate. Features include annotations like @GraphQLQuery, @GraphQLArgument, @GraphQLContext for type extension, and @GraphQLUnion for defining union types.

Tokens
1.6K
Snippets
6
Records
8
Agent score
28%

What's inside graphql-spqr

  1. Extend GraphQL types using @GraphQLContext

    master

    You can attach additional fields to an existing GraphQL type without modifying the original domain class. To do this, create a query in a service that takes the target type as a parameter annotated with @GraphQLContext. The parameter type becomes the 'context' for the new field.

    class UserService {
    
        // This method attaches a 'twitterProfile' field to the 'User' type
        @GraphQLQuery
        public TwitterProfile twitterProfile(@GraphQLContext User user) {
          // logic to fetch profile based on 'user'
          return ...;
        }
    }
  2. Install GraphQL SPQR via Maven or Gradle

    master

    Add the following dependency to your project to use GraphQL SPQR. Check Maven Central for the latest version.

    <dependency>
        <groupId>io.leangen.graphql</groupId>
        <artifactId>spqr</artifactId>
        <version>0.12.3</version>
    </dependency>
    compile 'io.leangen.graphql:spqr:0.12.3'
  3. Generate a GraphQL schema from Java services

    master

    GraphQL SPQR uses a code-first approach to generate a GraphQL schema from your existing Java models and services. You use the GraphQLSchemaGenerator to register service singletons and define the root packages to scan.

    Key steps:

    1. Annotate your service methods with @GraphQLQuery and arguments with @GraphQLArgument (optional if using -parameters compiler flag).
    2. Use GraphQLSchemaGenerator to build the schema.
    3. Build a GraphQL instance using the generated schema.
    UserService userService = new UserService();
    
    GraphQLSchema schema = new GraphQLSchemaGenerator()
        .withBasePackages("io.leangen") // Recommended: set your root packages
        .withOperationsFromSingleton(userService) // Register your service
        .generate();
    
    GraphQL graphQL = new GraphQL.Builder(schema)
        .build();
    
    // Execute queries
    ExecutionResult result = graphQL.execute(
        "{ user (id: 123) { name, regDate } }"
    );
  4. Resolve OpenJDK annotation duplication error

    master

    If you encounter AnnotationFormatError: Duplicate annotation for class: interface io.leangen.graphql.annotations.GraphQLNonNull, it is likely due to a bug in OpenJDK versions prior to 16 b17 regarding generic type parameter annotations.

    Workaround:

    • This issue occurs during compilation, not runtime.
    • If using IntelliJ IDEA, ensure the IDE is configured to use a system JDK (version 16 b17 or later) rather than the bundled JDK if the bundled version is affected.
  5. Configure Kotlin for GraphQL SPQR

    master

    To ensure best compatibility with Kotlin, you must use Kotlin 1.3.70 or later and include the following compiler argument:

    -Xemit-jvm-type-annotations

    This allows the Kotlin compiler to correctly produce type-use annotations required by the library.

  6. Use @GraphQLQuery and @GraphQLArgument annotations

    master

    While mapping is configurable, you can use these annotations to explicitly name GraphQL fields and arguments:

    • @GraphQLQuery(name = "...", description = "..."): Defines the name and description of a field or query in the schema.
    • @GraphQLArgument(name = "..."): Defines the name of a method argument in the GraphQL schema.

    Note: If you omit @GraphQLArgument, ensure you compile your code with the -parameters flag, otherwise argument names may be lost during schema generation.

    class UserService {
    
        @GraphQLQuery(name = "user")
        public User getById(@GraphQLArgument(name = "id") Integer id) {
          return ...;
        }
    }
  7. Implement a custom PossibleTypeFactory for @GraphQLUnion

    master

    If you need to dynamically determine the types that belong to a @GraphQLUnion, you can provide a custom implementation of the PossibleTypeFactory interface via the possibleTypeFactory() parameter in the @GraphQLUnion annotation. The factory must implement the getPossibleTypes() method, which returns a List<AnnotatedType> representing the valid types for the union.

    public class MyCustomFactory implements PossibleTypeFactory {
        @Override
        public List<AnnotatedType> getPossibleTypes() {
            // Logic to return list of AnnotatedType
            return myDynamicTypes;
        }
    }
    
    @GraphQLUnion(
        name = "DynamicUnion",
        possibleTypeFactory = MyCustomFactory.class
    )
    public interface DynamicUnion {}
  8. Define GraphQL Union types with @GraphQLUnion

    master

    Use the @GraphQLUnion annotation on a class to define a GraphQL Union type in your schema. A Union type represents an object that could be one of several different types.

    Key configuration options:

    • name(): The name of the Union type in the GraphQL schema.
    • description(): An optional description for the Union type.
    • possibleTypes(): An array of classes that are valid members of this Union.
    • possibleTypeFactory(): A custom implementation of PossibleTypeFactory used to dynamically determine the possible types.
    • possibleTypeAutoDiscovery(): A boolean flag to enable/disable automatic discovery of possible types.
    • scanPackages(): An array of package names to scan if possibleTypeAutoDiscovery is enabled.
    @GraphQLUnion(
        name = "SearchResult",
        description = "A search result that can be a User or a Post",
        possibleTypes = {User.class, Post.class}
    )
    public interface SearchResult {}