Simplificator 3000 is a package containing various helpers for easier work in Phoenix.
If available in Hex, the package can be installed
by adding simplificator_3000_phoenix
to your list of dependencies in mix.exs
:
def deps do
[
{:simplificator_3000_phoenix, "~> 1.0.0"}
]
end
Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/simplificator_3000_phoenix.
Package contains macros for standardizing communications in channels and api endpoints. In both channel and api handler you set required params/payload scheme (using tarams), check required permission, groups or roles. You can configure everything either for whole app (in config) or just one method
Just import Simplificator3000Phoenix.ApiHandler
then you use
api_handler(action_name,params_scheme,optional_options)
to define action and then create handler for given action which needs to be named action + postfix ("_handler" by default). Handler will be called only after permissions are check and params validated and parsed.
Minimal usage
api_handler(:minimal, %{})
def minimal_handler(conn, _params) do
ok("hello there")
end
With params scheme (see Tarams for scheme definition)
@number_scheme %{
number: [type: :integer, number: [greater_than: 0], required: true]
}
api_handler(:minimal_parameters, @number_scheme, fallback_options: [full_error: true])
def minimal_parameters_handler(conn, %{number: num}) do
case num do
1 -> ok(%{three_times_bigger: num * 3})
2 -> ok(%{three_times_bigger: num * 3}, %{data: "no this is metadata"})
3 -> error(reason: :who_not, msg: "message", response_code: 501)
4 -> {:error, :some_error_stuff}
end
end
To return data use ok or error macro (variable named conn has to be defined to use them). You can also return just conn if you want to manually reply. If you return anything else than {conn,_} or conn it will be handeled by fallback handler. You can enable/disable fallback handler with :fallback_enabled
. You can also pass arguments to fallback handler with :fallback_options
.
Default fallback handler return 500 internal server error by default, if you set fallback_options: [full_error: true]
it will return inspected error as detail
With nested scheme
@nested_scheme %{
name: :string,
email: [type: :string, required: true],
addresses: [
type:
{
:array,
%{
street: :string,
district: :string,
city: :string,
zip_code: [type: :integer, number: [min: 10_000, max: 99_999]]
}
}
]
}
api_handler(:nested, @nested_scheme)
def nested_handler(conn, params) do
ok(params)
end
With permissions check
@params_scheme %{
permissions: [type: {:array, :string}],
groups: [type: {:array, :string}],
roles: [type: {:array, :string}]
}
api_handler(:action, @params_scheme,
roles: {["role", "role1"], :and},
groups: ["group"],
permissions: ["permission"]
)
def action_handler(conn, params) do
ok(params)
end
when you require permission/groups/roles, you either pass list of required stuff, or {list,operator }. Handler method will be called with (conn/socket, {type,required_stuff} || {type,required_stuff,operator} )
and you handler will return true/false
:unauthorized_handler
will be called if request is not authorized
config :simplificator_3000_phoenix,
api_handler: %{
# configuration goes here
},
key | type | detail |
---|---|---|
handler_postfix | string | |
response_handler | func(conn,handler_return) -> (conn) | |
invalid_params_handler | func(conn,params_error) -> (conn) | |
fallback_handler | func(conn,error,options) -> (conn) | |
fallback_enabled | boolean | |
auth_handler | func(conn,required) -> boolean | |
auth_operator | :or or :and | |
unauthorized_handler | func(conn) -> conn |
add use Simplificator3000Phoenix.Channel
Now replace join funtion with this
def join("topic", payload, socket) do
if authorized?("topic", payload, socket) do
#required permission are check, you can check more stuff here before acception join
{:ok, socket}
else
unauthorized(socket)
end
end
to check permissions when joining channel
use Simplificator3000Phoenix.Channel, permissions: ["permissions"], roles: {["role1",:and]}
to add handler for message use
message(event,params_scheme,options)
it is simular to api_handler
except it doesnt have fallback controller and handler method has same name as event
return (success/error)_(reply/push) to respond or no_reply to dont
examples:
message(:test, %{})
def test(socket, _payload) do
success_reply(socket, "hello")
end
message(
:number,
%{number_with: [type: :integer, required: true]},
permissions: {["group2", "group3"], :and}
)
def number(socket, payload) do
success_reply(socket, inspect(payload))
end
message(
:async,
%{number_with: [type: :integer, required: true]},
roles: ["group1"]
)
def async(socket, payload) do
Task.start_link(fn ->
success_reply(socket, inspect(payload))
end)
no_reply()
end
to add pubsub handler use sub(event)
and define handler event(socket,message)
pubsub messages need to have following format {event,message}
example:
message(:send_after)
def send_after(socket, _payload) do
#simulate pubsub message
Process.send_after(self(), {:hello, %{message: "hello future me"}}, 1000)
no_reply()
end
sub(:hello)
def hello(socket, message) do
IO.puts("HELLo")
success_push(socket, "reply", message.message)
end
config :simplificator_3000_phoenix,
channel: %{
# configuration goes here
},
key | type | detail |
---|---|---|
invalid_params_handler | func(conn,params_error) -> (conn) | |
unauthorized_handler | func(conn) -> conn |
Example configuration
Only thing you have to configure is auth_handler (only if you use permissions, groups or roles)
config :simplificator_3000_phoenix,
auth_operator:
auth_handler:
api_handler: %{
#api handler configuration
},
channel: %{
#channel configuration
}