Submitting Subscriptions

Now that we can create orders, we’re at the perfect spot to introduce the first basic subscription that will support pushing these orders as they’re created out to subscribed clients. You’ll first need to define a subscription field in your schema, and then you’ll also need a way to actually trigger this subscription when the :place_order mutation runs.

 subscription ​do
  field ​:new_order​, ​:order​ ​do
 
  config ​fn​ _args, _info ->
  {​:ok​, ​topic:​ ​"​​*"​}
 end
 end
 end

For the most part, this is a pretty ordinary-looking field. We’ve got another top-level object, subscription, to house our subscription fields, and then the :new_order, which will return the :order object we’re already familiar with. The fact that it returns a regular :order object is crucial, because this means that all the work we have done to support the output of the mutation can be reused immediately for real-time data.

What’s new, however, is the config macro, and it’s one of a couple macros that are specific to setting up subscriptions. The job of the config macro is to help us determine which clients who have asked for a given subscription field should receive data by configuring a topic. We’ll talk more later about constructing topics, but the main thing to know is that topics are scoped to the field they’re on, and they have to be a string. We’re just going to use "*" to indicate that we care about all orders (but there’s nothing special about "*" itself).

Set Up and Return Error

images/aside-icons/tip.png

The config function can also return {:error, reason}, which prevents the subscription from being created.

Let’s see if we can subscribe with GraphiQL. First, let’s make sure it’s running again, but this time, inside an IEx session (you’ll see why shortly):

 $ ​​iex​​ ​​-S​​ ​​mix​​ ​​phx.server
 [info] Running PlateSlateWeb.Endpoint with Cowboy using http://0.0.0.0:4000

Then, browse to http://localhost:4000/graphiql and enter the following in the left-side panel (you can close the “Query Variables” panel if you have it open):

 subscription​ {
  newOrder {
  customerNumber
  items { name quantity}
  }
 }

When you hit “play,” instead of getting a result, you’ll get a message saying, "Your subscription data will appear here after server publication!":

images/chp.subscriptions/graphiql-3.png

What’s happening here is that although the server has accepted the subscription document, the server is waiting on some kind of event that will trigger execution of the document and distribution of the result. Specifically, it’s waiting for an event that targets the field of our subscription newOrder and the topic associated with this specific document "*".

The most direct way to make this trigger happen is with the Absinthe.Subscription.publish/3 function, which gives us manual control of the publishing mechanism. If you go into the IEx session in your console, you can trigger the subscription you just created in GraphiQL by running:

 iex>​ order = PlateSlate.Ordering.Order |> PlateSlate.Repo.all |> List.last
 %PlateSlate.Ordering.Order{} displayed
 iex>​ Absinthe.Subscription.publish(
  PlateSlateWeb.Endpoint,
  order,
  new_order: "​*​"
 )
 :ok

If you look back to your GraphiQL page, you should see a result as shown in the figure.

images/chp.subscriptions/graphiql-4.png

The arguments to the publish/3 function are the module you’re using as the pubsub, the value that you’re broadcasting, and the field: topic pairs at which to broadcast the value. Concretely then, the function call you typed in IEx says to broadcast the last %Order{} struct to all clients subscribed to the :new_order field via the "*" topic.

You may have noticed when you set up the subscription field that you didn’t specify a resolver, and this is why. Unlike a root query or root mutation resolver, which generally starts with no root value and has to start from scratch, the root value of a subscription document is the value that is passed to publish/3. You can see this for yourself if you add just an inspect resolver to the subscription field:

 subscription ​do
  field ​:new_order​, ​:order​ ​do
 
  config ​fn​ _args, _info ->
  {​:ok​, ​topic:​ ​"​​*"​}
 end
 
» resolve ​fn​ root, _, _ ->
» IO.inspect(root)
» {​:ok​, root}
»end
 end
 end

If you re-run the Absinthe.Subscription.publish/3 call in your IEx session, you will see printed into console the value you are broadcasting, nested under the :new_order key:

 %Ordering.Order{
  Contents
 }

With this Absinthe.Subscription.publish/3 function at our disposal, it’s clear then that one possibility for making our live interface is to put it inside the :place_order mutation resolver so that instead of triggering subscriptions from IEx, we’ll trigger subscriptions every time a new order is placed.

 def​ place_order(_, %{​input:​ place_order_input}, _) ​do
 case​ Ordering.create_order(place_order_input) ​do
  {​:ok​, order} ->
» Absinthe.Subscription.publish(PlateSlateWeb.Endpoint, order,
»new_order:​ ​"​​*"
» )
  {​:ok​, %{​order:​ order}}
  {​:error​, changeset} ->
  {​:ok​, %{​errors:​ transform_errors(changeset)}}
 end
 end

You could have some fun with this:

  • In one window, open GraphiQL and enter the subscription document.
  • In another window, also go to GraphiQL and enter the mutation document.
  • Press “play” in the mutation window.
  • Watch real-time events show up in the subscription window!

Play around with changing what parts of the subscription document you ask for, and play around with the values you put in the mutation document to get a feel for how the two documents relate to one another.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.70.185