Grapple
🍏 Webhook magic in Elixir
Installation
If available in Hex, the package can be installed as:
- Add
grappleto your list of dependencies inmix.exs:
```elixir
def deps do
[{:grapple, "~> 0.2.0"}]
end
```
- Ensure
grappleis started before your application:
```elixir
def application do
[applications: [:grapple]]
end
``
Running
iex -S mix
Documentation
https://hexdocs.pm/grapple/0.1.0
Direct API Usage
The default struct, %Grapple.Hook{}, has the following fields: topic, url, owner, life, ref, method, headers, body, and query. Note that topic and url are required. TODO: make this configurable.
To subscribe to a webhook, pass a Hook to the subscribe function, which returns the topic name and the unique refernce to that particular hook:
hook = %Grapple.Hook{topic: "pokemon", url: "http://pokeapi.co/api/v2/pokemon/149"}
{topic, ref} = Grapple.Hook.subscribe(hook)
To broadcast a webhook, pass a topic, and optionally arbitrary data.
This will trigger HTTP requests for any stored hooks whose topic values match the given topic, and return the parsed responses.
# this will send hooks with their default `body`
[response] = Grapple.Hook.broadcast("pokemon")
# can also pass arbitrary data that will be sent instead
[response] = Grapple.Hook.broadcast("pokemon", data)
Responses will take one of the following forms:
# on success
{:success, body: body} = response
# on 404
:not_found = response
# on error
{:error, reason: reason} = response
Macro Usage
Broadcasting can also be done via a macro, defhook. Its name will be used in the topic (takes the form "#{MODULE}.#{name}"). Its result will be passed as the body to any hook requests on that topic, unless it returns nil, in which case hooks will be sent with default body.
hook = %Grapple.Hook{topic: "Pokemon.dragonite", url: "http://pokeapi.co/api/v2/pokemon/149"}
defmodule Pokemon do
use Grapple.Hook
# in this case, no body needed
defhook dragonite do
# add other logic, and return body or return nil
nil
end
end
Plug Usage
Finally, broadcasting can be done with Grapple.Plug. Here's an example from a Phoenix Controller:
defmodule Pokedex.PokemonController do
use Pokedex.Web, :controller
plug Grapple.Plug, [topic: "pokemon"] when action in [:get]
def get(conn, _opts) do
conn
end
end