absinthe-graphql / absinthe_graphql_ws

Add graphql-ws websocket transport for Absinthe
https://hexdocs.pm/absinthe_graphql_ws/overview.html
MIT License
66 stars 20 forks source link
elixir graphql

AbsintheGraphqlWS

Adds a websocket transport for the GraphQL over WebSocket Protocol to Absinthe running in Phoenix.

See the hex docs for more information.

References

Installation

Add absinthe_graphql_ws to your list of dependencies in mix.exs:

def deps do
  [
    {:absinthe_graphql_ws, "~> 0.3"}
  ]
end

Usage

Using the websocket client

defmodule ExampleWeb.ApiClient do
  use GenServer

  alias Absinthe.GraphqlWS.Client

  def start(endpoint) do
    Client.start(endpoint)
  end

  def init(args) do
    {:ok, args}
  end

  def stop(client) do
    Client.close(client)
  end

  @gql """
  mutation ChangeSomething($id: String!) {
    changeSomething(id: $id) {
      id
      name
    }
  }
  """
  def change_something(client, thing_id) do
    {:ok, body} = Client.query(client, @gql, id: thing_id)

    case get_in(body, ~w[data changeSomething]) do
      nil -> {:error, get_in(body, ~w[errors])}
      thing -> {:ok, thing}
    end
  end

  @gql """
  query GetSomething($id: UUID!) {
    thing(id: $id) {
      id
      name
    }
  }
  """
  def get_thing(client, thing_id) do
    case Client.query(client, @gql, id: thing_id) do
      {:ok, %{"data" => %{"thing" => nil}}} ->
        nil

      {:ok, %{"data" => %{"thing" => result}}} ->
        {:ok, result}

      {:ok, errors} when is_list(errors) ->
        nil
    end
  end

  @gql """
  subscription ThingChanges($thingId: String!){
    thingChanges(thingId: $projectId) {
      id
      name
    }
  }
  """
  # handler is a pid for a process that implements `handle_info/4` as below
  def thing_changes(client, thing_id: thing_id, handler: handler) do
    Client.subscribe(client, @gql, %{thingId: thing_id}, handler)
  end
end

An example of handle_info

  @impl true
  def handle_info({:subscription, _id, %{"data" => %{"thingChanges" => thing_changes}}}, %{assigns: %{thing: thing}} = socket) do
    changes = thing_changes |> Enum.find(&(&1["id"] == thing.id))
    socket |> do_cool_update(changes["things"]) |> noreply()
  end

Benchmarks

Benchmarks live in the benchmarks directory, and can be run with MIX_ENV=bench mix run benchmarks/<file>.

Contributing