Skip to content

Latest commit

 

History

History
132 lines (108 loc) · 5.24 KB

File metadata and controls

132 lines (108 loc) · 5.24 KB

Subscription HTTP Callback Support for Spring GraphQL

GraphQL subscriptions enable clients to receive continual, real-time updates whenever new data becomes available. Unlike queries and mutations, subscriptions are long-lasting. This means a client can receive multiple updates from a single subscription.

Spring GraphQL provides out of box support for GraphQL subscriptions over WebSockets using graphql-transport-ws protocol. This library adds support for subscriptions using Apollo HTTP callback protocol.

See Apollo Router for additional details about Federation and Subscription support.

sequenceDiagram;
  Router->>Spring GraphQL Server: Register subscription and callback URL over HTTP
  Note over Spring GraphQL Server: Initialize protocol
  Spring GraphQL Server->>Router: check
  Router->>Spring GraphQL Server: HTTP 204 No Content
  Note over Spring GraphQL Server: Start subsciption and heartbeat<br>on background threads
  Spring GraphQL Server->>Router: HTTP 200 OK<br>{ "data": null }
  Note over Router: Time passes
  par Subscription to Router
      Note over Subscription: While data available
      loop Data Available
          Subscription->>Router: next<br>{ "data": <subscriptionData> }
          Router->>Subscription: HTTP 200 OK
      end
      Note over Subscription: Subscription Complete/Error
      Subscription->>Router: complete
      Router->>Subscription: HTTP 202 Accepted
  and Heartbeat to Router
      loop Emit every 5 seconds
          Heartbeat->>Router: check
          Router->>Heartbeat: HTTP 204 No Content
      end
  end

Installation

Federation JVM libraries are published to Maven Central. Using a JVM dependency manager, link federation-spring-subscription-callback to your project.

With Maven:

<dependency>
  <groupId>com.apollographql.federation</groupId>
  <artifactId>federation-spring-subscription-callback</artifactId>
  <version>${latestVersion}</version>
</dependency>

With Gradle (Kotlin):

implementation("com.apollographql.federation:federation-spring-subscription-callback:$latestVersion")

Usage

In order to enable HTTP subscription callback protocol support you need to configure CallbackGraphQlHttpHandler bean in your application context.

This library provides support for both WebMVC and WebFlux applications so make sure to instantiate correct flavor of protocol.

  • com.apollographql.subscription.webmvc.CallbackGraphQlHttpHandler for WebMVC applications
  • com.apollographql.subscription.webflux.CallbackGraphQlHttpHandler for WebFlux applications

Given a subscription

@Controller
public class MySubscriptionController {

    @SubscriptionMapping
    public Flux<Integer> counter() {
        return Flux.just(1, 2, 3, 4, 5, 6)
                .delayElements(Duration.ofMillis(200));
    }
}

We can enable subscription HTTP callback support using following configuration

@Configuration
public class GraphQLConfiguration {

    @Bean
    public GraphQlHttpHandler graphQlHttpHandler(WebGraphQlHandler webGraphQlHandler) {
        return new CallbackGraphQlHttpHandler(webGraphQlHandler);
    }

    // regular federation transform
    @Bean
    public GraphQlSourceBuilderCustomizer federationTransform() {
        DataFetcher<?> entityDataFetcher =
                env -> {
                    List<Map<String, Object>> representations = env.getArgument(_Entity.argumentName);
                    return representations.stream()
                            .map(
                                    representation -> {
                                        // TODO implement entity data fetcher logic here
                                        return null;
                                    })
                            .collect(Collectors.toList());
                };

        return builder ->
                builder.schemaFactory(
                        (registry, wiring) ->
                                Federation.transform(registry, wiring)
                                        .fetchEntities(entityDataFetcher)
                                        .resolveEntityType(new ClassNameTypeResolver())
                                        .build());
    }
}

By default, subscription and heartbeat stream will be executed in non-blocking way on bounded elastic scheduler. If you need more granular control over the underlying scheduler, you can configure callback handler to run on your provided scheduler.

@Bean
public GraphQlHttpHandler graphQlHttpHandler(WebGraphQlHandler webGraphQlHandler) {
    Scheduler customScheduler = <provide your custom scheduler>;
    SubscriptionCallbackHandler subscriptionHandler = new SubscriptionCallbackHandler(webGraphQlHandler, customScheduler);
    return new CallbackGraphQlHttpHandler(webGraphQlHandler, subscriptionHandler);
}