graphql-java - How to use subscriptions with spring boot?

后端 未结 3 1666
青春惊慌失措
青春惊慌失措 2021-02-04 14:16

In a project I use graphql-java and spring boot with a postgreSQL Database. Now I would like to use the subscription feature

相关标签:
3条回答
  • 2021-02-04 14:59

    For the record: here is another very nice, compact example that implements GraphQLs essential features queries, mutations and subscriptions: https://github.com/npalm/blog-graphql-spring-service

    0 讨论(0)
  • 2021-02-04 15:00

    As of recent graphql-java versions, subscriptions are fully supported. The DataFetcher for a subscription must return a org.reactivestreams.Publisher, and graphql-java will take care of mapping the query function over the results.

    The feature is nicely documented and there's a complete example using web sockets available in the official repo.

    If you have a reactive data source in place (e.g. Mongo with a reactive driver, or probably anything that R2DBC supports), you're all set. Just use @Tailable and Spring Data will already give you a Flux (which implements Publisher) and there's nothing else you need to do.

    As for a more manual Spring specific implementation, I can't imagine it being too hard to use Spring's own event mechanism (a nice tutorial here as well) to underlie the Publisher.

    Every time there's an incoming subscription, create and register a new listener with the application context: context.addApplicationListener(listener) that will publish to the correct Publisher. E.g. in the DataFetcher:

    // Somehow create a publisher, probably using Spring's Reactor project. Or RxJava.
    Publisher<ResultObject> publisher = ...; 
    //The listener reacts on application events and pushes new values through the publisher
    ApplicationListener listener = createListener(publisher);
    context.addApplicationListener(listener);
    return publisher;
    

    When the web socket disconnects or you somehow know the event stream is finished, you must make sure to remove the listener.

    I haven't actually tried any of this, mind you, I'm just thinking aloud.

    Another option is to use Reactor directly (with or without Spring WebFlux). There's a sample using Reactor and WebSocket (through GraphQL SPQR Spring Boot Starter) here.

    You create a Publisher like this:

    //This is really just a thread-safe wrapper around Map<String, Set<FluxSink<Task>>>
    private final ConcurrentMultiRegistry<String, FluxSink<Task>> subscribers = new ConcurrentMultiRegistry<>();
    
    @GraphQLSubscription
    public Publisher<Task> taskStatusChanged(String taskId) {
        return Flux.create(subscriber -> subscribers.add(taskId, subscriber.onDispose(() -> subscribers.remove(taskId, subscriber))), FluxSink.OverflowStrategy.LATEST);
    }
    

    And then push new values from elsewhere (probably a related mutation or a reactive storage) like this:

    subscribers.get(taskId).forEach(subscriber -> subscriber.next(task));
    

    E.g.

    @GraphQLMutation
    public Task updateTask(@GraphQLNonNull String taskId, @GraphQLNonNull Status status) {
        Task task = repo.byId(taskId); //find the task
        task.setStatus(status); //update the task
        repo.save(task); //persist the task
        //Notify all the subscribers following this task
        subscribers.get(taskId).forEach(subscriber -> subscriber.next(task));
        return task;
    }
    

    With SPQR Spring Starter, this is all that's needed to get you an Apollo-compatible subscription implementation.

    0 讨论(0)
  • 2021-02-04 15:11

    I got the same issue where I was spiking on the lib to integrate with spring boot. I found graphql-java, however, it seems it only support 'subscription' on schema level, it is not perform any transnational support for this feature. Meaning you might need to implement it your self.

    Please refer to https://github.com/graphql-java/graphql-java/blob/master/docs/schema.rst#subscription-support

    0 讨论(0)
提交回复
热议问题