Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/implicitly-awesome/exop_plug
Provides a convenient way to validate incoming parameters of your Phoenix application's controllers by offering you small but useful DSL.
https://github.com/implicitly-awesome/exop_plug
List: exop_plug
coercion elixir phoenix validation
Last synced: 3 months ago
JSON representation
Provides a convenient way to validate incoming parameters of your Phoenix application's controllers by offering you small but useful DSL.
- Host: GitHub
- URL: https://github.com/implicitly-awesome/exop_plug
- Owner: implicitly-awesome
- License: mit
- Created: 2019-10-21T09:36:23.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2020-03-06T11:19:03.000Z (over 4 years ago)
- Last Synced: 2024-04-14T11:55:35.365Z (7 months ago)
- Topics: coercion, elixir, phoenix, validation
- Language: Elixir
- Homepage:
- Size: 34.2 KB
- Stars: 6
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
[![Hex.pm](https://img.shields.io/hexpm/v/exop_plug.svg)](https://hex.pm/packages/exop_plug) [![API Docs](https://img.shields.io/badge/api-docs-yellow.svg?style=flat)](http://hexdocs.pm/exop_plug/) [![Build Status](https://travis-ci.org/madeinussr/exop_plug.svg?branch=master)](https://travis-ci.org/madeinussr/exop_plug)
# ExopPlug
This library provides a convenient way to validate incoming parameters
of your Phoenix application's controllers by offering you small but useful DSL
which makes as little magic behind the scenes as possible leaves you all the control
under HTTP request.## Table of Contents
[CHANGELOG](https://github.com/madeinussr/exop_plug/blob/master/CHANGELOG.md)
- [Installation](#installation)
- [How it works](#how-it-works)
- [Step-by-step](#step-by-step)
- [1. create a plug](#1-create-a-plug)
- [2. in a controller](#2-in-a-controller)
- [More examples](#more-examples)
- [coercing](#coercing)
- [rely on `action_fallback`](#rely-on-action_fallback)
- [respond directly from `on_fail` callback](#respond-directly-from-on_fail-callback)
- [LICENSE](#license)## Installation
```elixir
def deps do
[
{:exop, "~> 1.4"},
{:exop_plug, "~> 1.1"}
]
end
```## How it works
Basically speaking ExopPlug utilizes the power of [Exop](https://github.com/madeinussr/exop) library
by generating in compile time Exop-operations for your actions defined in a plug.So, you define a plug with number of actions and parameters with validation checks.
Then you use this plug in corresponding controller and that's it: once HTTP request comes,
your controller's plug takes an action: it figures out whether this particular HTTP request's
parameters should be validated or not, and if yes - validates them.If parameters pass the validation ExopPlug returns `Plug.Conn` (as usual plug does),
if not - it returns [Exop's](https://github.com/madeinussr/exop) error-tuple as described
[here](https://github.com/madeinussr/exop#operation-results). And it is up to you then to decide
how you want to handle the result.Please keep in mind: ExopPlug doesn't transform your HTTP request nor `Plug.Conn.t()` structure.
So, if you define `get '/user/:user_id'` in your router you receive `%{"user_id" => "1"}` for
the request `http://localhost:4000/user/1`. There is no any coercion or type inference done
under the scenes._(if such feature(-s) will be requested, they'll be added and you'll need to specify them
explicitly in an action definition)_## Step-by-step
### 1. create a plug
Create a new module plug and define actions with parameters you want to validate.
A parameter's validations are the same as Exop has for an operation parameter checks.
You can find all them [here](https://github.com/madeinussr/exop#parameter-checks)
along with other features like coercion.```elixir
defmodule MyAppWeb.UserControllerPlug do
use ExopPlugaction(:show, params: %{"id" => [type: :string, length: %{min: 5}]}, on_fail: &__MODULE__.on_fail/3)
def on_fail(conn, action_name, errors_map) do
Plug.Conn.assign(conn, :errors, errors_map)
end
end
```Here we also defined an `on_fail` callback. This 3-arity function is called when an action's parameters
failed the specified validation.### 2. in a controller
Simply add `plug MyAppWeb.UserControllerPlug` at the top of your controller.
```elixir
defmodule MyAppWeb.UserController do
use MyAppWeb, :controllerplug MyAppWeb.UserControllerPlug
# ...
def show(conn, params) do
json(conn, params)
end# ...
end
```Now, if you receive invalid parameters for your `show` you get (for example)
`errors: %{"id" => ["has wrong type"]}}` within your `Plug.Conn` assigns
(as you earlier specified in your plug). And then it is up to you how to deal with this errors map.## More examples
The power of ExopPlug actually is provided by Exop and its validation capabilities.
Basically, every check you use in Exop you can apply for an action's parameter in your plug.Below I put a couple of examples just in order to show different checks and things you can do with
a parameter or validation errors.### coercing
In the example above there is one tricky thing which I've just omit for the sake of example:
with `get '/user/:user_id'` route you'll get `user_id` parameter as string, always, because it is
path parameter.But you can coerce it before the validation:
```elixir
action(:show, params: %{"id" => [type: :integer, coerce_with: &__MODULE__.coerce_integer/2]})def coerce_integer({_, param_value}, _) when is_binary(param_value) do
{integer, ""} = Integer.parse(param_value)
integer
end
```_(and again: read more about `:coerce_with` option in Exop [docs](https://github.com/madeinussr/exop))_
### rely on `action_fallback`
After assigning errors to a connection you can later pattern-match it in a controller's action
and invoke your `action_fallback`'s fallback controller:```elixir
# in a plug ...action(:show, params: %{"id" => [type: :integer]}, on_fail: &__MODULE__.on_fail/3)
def on_fail(conn, action_name, errors_map) do
Plug.Conn.assign(conn, :errors, errors_map)
end# in a controller ...
action_fallback MyAppWeb.FallbackController
def show(%Plug.Conn{assigns: %{errors: errors_map}}, _params) do
{:error, errors_map}
end# in the fallback controller ...
def call(conn, {:error, errors_map}) do
json(conn, errors_map)
end
```### respond directly from `on_fail` callback
It might be useful not to assign validation errors to a connection, but respond immediately:
```elixir
action(:show, params: %{"id" => [type: :integer]}, on_fail: &__MODULE__.on_fail/3)def on_fail(conn, action_name, errors_map) do
response = %{
action: action_name,
errors: errors_map
}Phoenix.Controller.json(conn, response)
end
```## LICENSE
Copyright © 2019 - 2020 Andrey Chernykh ( [email protected] )
This work is free. You can redistribute it and/or modify it under the
terms of the MIT License. See the LICENSE file for more details.