Subscriptions let a client submit a GraphQL document that, instead of being executed immediately, is executed on the basis of some event in the system. From the perspective of the server, we need to be able to hold onto documents that clients have submitted so that we can run them at the right time, and we need a way to propagate events through the system. Finally, we need a way to have a persistent connection with the client so that we can push results up to them when their documents are executed.
This requires a little bit of setup. Fortunately, PlateSlate already has Phoenix as a dependency, and that will play the role of the publish-subscribe[22] and WebSocket system. This provides a number of handy features for free: clients will be able to use long polling or WebSockets, and the pubsub will work either over distributed Elixir or through any other adapter (like Redis) built to work with Phoenix pubsub. However, there are a few things you need to do to connect these capabilities to Absinthe.
The first order of business is to add an Absinthe.Subscription supervisor to the PlateSlate application’s supervision tree by modifying the children list in the start/2 callback of application.ex.
| def start(_type, _args) do |
| import Supervisor.Spec |
| |
| children = [ |
| supervisor(PlateSlate.Repo, []), |
| supervisor(PlateSlateWeb.Endpoint, []), |
» | supervisor(Absinthe.Subscription, [PlateSlateWeb.Endpoint]), |
| ] |
| opts = [strategy: :one_for_one, name: PlateSlate.Supervisor] |
| Supervisor.start_link(children, opts) |
| end |
This Absinthe.Subscription supervisor starts a number of processes that will handle broadcasting results and hold on to subscription documents. You pass the supervisor your PlateSlateWeb.Endpoint module because you’re using the Phoenix endpoint as the underlying pubsub mechanism.
Phoenix Not Required | |
---|---|
We’re using Phoenix as the pubsub for our subscriptions in this chapter because it’s a powerful system and easy to get started with. Absinthe’s support for subscriptions is flexible enough to be used outside of WebSockets (or even the browser); we’ll cover some ideas in later chapters. |
Speaking of the Phoenix endpoint, we need to add a single line to its definition to provide a few extra callbacks that Absinthe expects:
| defmodule PlateSlateWeb.Endpoint do |
| use Phoenix.Endpoint, otp_app: :plate_slate |
» | use Absinthe.Phoenix.Endpoint |
| |
| # Rest of file |
| end |
Here we see the first use of the Absinthe.Phoenix project. Much like Absinthe.Plug provides a way to use Absinthe from within a Plug pipeline, Absinthe.Phoenix provides a way to use Absinthe from within Phoenix-specific features like channels.[23]
With the actual pubsub stuff set up, we just need to configure our socket. Inside PlateSlateWeb.UserSocket, add:
| defmodule PlateSlateWeb.UserSocket do |
| use Phoenix.Socket |
» | use Absinthe.Phoenix.Socket, schema: PlateSlateWeb.Schema |
| |
| # Rest of file |
| end |
Last but not least, we need to configure GraphiQL to use this socket:
| forward "/graphiql", Absinthe.Plug.GraphiQL, |
| schema: PlateSlateWeb.Schema, |
| interface: :simple, |
» | socket: PlateSlateWeb.UserSocket |
And with those four lines added, all the underlying mechanisms are wired up. Let’s build an ordering system.
3.15.189.199