Current section
Files
Jump to
Current section
Files
lib/txpost/router.ex
defmodule Txpost.Router do
@moduledoc """
Very simple router behaviour so your can advertise a single route to handle
all incoming transactions.
Define a module that implements the `c:handle_tx/2` callback. For example:
defmodule MyApp.TxRouter do
use Txpost.Router
def handle_tx(conn, _params) do
case get_req_meta(conn) do
%{"type" => "article"} -> ArticleController.call(conn, :create)
%{"type" => "image"} -> ImageController.call(conn, :create)
end
end
end
The `c:handle_tx/2` callback gives you access to the connection and request
parameters, meaning you can use any part of the request, including headers,
request meta data or the raw transaction itself, and call the appropriate
action to handle the request.
As the router is a plug, you can add a single route to your main router to
handle all incoming transactions. For example, a Phoenix router
implementation may look like:
defmodule MyApp.Router do
use MyApp, :router
pipeline :tx_api do
plug :accepts, ["cbor"]
plug Txpost.Plug
end
scope "/tx" do
pipe_through :tx_api
post "/", MyApp.TxRouter, []
end
end
Alternatively, implemented using a Plug router may look like:
defmodule MyApp.Router do
use Plug.Router
plug :match
plug Plug.Parsers, parsers: [Txpost.Parsers.CBOR]
plug Txpost.Plug
plug :dispatch
post "/tx", to: MyApp.TxRouter
end
"""
@doc false
defmacro __using__(_opts) do
quote do
import Plug.Conn
import Txpost.Router
@behaviour Plug
@impl true
def init(opts), do: opts
@impl true
def call(conn, _opts), do: handle_tx(conn, conn.params)
end
end
@doc """
Invoked to handle incoming requests.
Function recieves the connection and request parameters which will include the
raw transaction.
Any logic can be used the determine the correct route, and call any "action"
function that adheres to the Plug specification and returns the connection.
## Examples
Use the request meta data to route the request:
def handle_tx(conn, params) do
case get_req_meta(conn) do
%{"type" => "article"} -> ArticleController.create(conn, params)
%{"type" => "image"} -> ImageController.create(conn, params)
end
end
Use Shapeshifter to decode the raw transaction.
def handle_tx(conn, %{"rawtx" => rawtx}) do
[output | _] = rawtx
|> Shapeshifter.to_txo
|> Map.get("out")
case output do
%{"s3" => "article"} -> ArticleController.call(conn, :create)
%{"s3" => "image"} -> ImageController.call(conn, :create)
end
end
"""
@callback handle_tx(conn :: Plug.Conn.t, params :: map | list(map)) :: Plug.Conn.t
@doc """
Returns the request payload meta data.
"""
@spec get_req_meta(Plug.Conn.t) :: map | nil
def get_req_meta(%{private: %{txpost_payload: payload}} = _conn), do: payload.meta
def get_req_meta(%{params: %{"meta" => meta}}), do: meta
def get_req_meta(_conn), do: nil
end