rubyruby-grapegrape-apiwisper

Wisper and Grape return results from a POST request


I have a simple POST Grape endpoint with Wisper pub/sub in a background:

module Something
  class Doit < Grape::API
    post :now do
      service = SomePub.new
      service.subscribe(SomeSub.new)
      service.call(params)
    end
  end
end

Here is the SomeSub where actually calculations happens:

class SomeSub
  def do_calculations(payload)
     {result: "42"}.to_json
  end
end

SomePub is simple too:

class SomePub
  include Wisper::Publisher

  def call(payload)
    broadcast(:do_calculations, payload)
  end
end

So what I need is to respond with the JSON {result: "42"}, when calling the Grape's post :now endpoint.

Unfortunately it doesn't work this way, and what I have is:

{"local_registrations":[{"listener":{},"on":{},"with":null,"prefix":"","allowed_classes":[],"broadcaster":{}}]}

That example from Wisper's wiki doesn't help too much (https://github.com/krisleech/wisper/wiki/Grape)

Any ideas how to actually pass SomePub#do_calculations results, as a result of Grape's endpoint call?


Solution

  • The point of PubSub pattern is that Publisher is completely unaware of its subscribers. What you are trying to achieve is to pass Subscriber's result back to Publisher, which is against all of the idea.

    What you can do, however, is to make your subscriber also a publisher and collect responses in a separate subscriber.

    Please, note, that this is sample code as I don't have Grape installed at hand (but, hopefully, it works):

    class ResponseListener
      attr_reader :response
    
      def initialize
        @response = {}
      end
    
      def collect_response(item)
        @response.merge!(item) # customize as you wish
      end
    end
    
    class SomeSub
      include Wisper::Publisher
    
      def do_calculations(payload)
         broadcast(:collect_response, result: "42")
      end
    end
    
    module Something
      class Doit < Grape::API
        post :now do
          response_listener = ResponseListener.new
          # globally subscribe response_listener to all events it can respond to
          Wisper.subscribe(response_listener) 
    
          service = SomePub.new
          service.subscribe(SomeSub.new)
          service.call(params)
    
          response_listener.response.to_json # render collected response
        end
      end
    end