Current section
10 Versions
Jump to
Current section
10 Versions
Compare versions
8
files changed
+65
additions
-54
deletions
| @@ -5,11 +5,11 @@ DRY up your Phoenix controllers. | |
| 5 5 | ## Features |
| 6 6 | |
| 7 7 | - Turns controllers into declarative code. |
| 8 | - - Works with any context function that returns a tagged tuple like `{:ok, ...}` or `{:error, ...}` |
| 9 | - - Understands `Ecto.Changeset` errors and can render the error. |
| 10 | - - Built in responders for JSON and HTML and ability to create custom ones. |
| 8 | + - Works with all context functions that return a tagged tuple like `{:ok, ...}` or `{:error, ...}` |
| 9 | + - Supports rendering `Ecto.Changeset` errors. |
| 10 | + - Built-in formatters for JSON and HTML with ability to add custom ones. |
| 11 11 | |
| 12 | - **Disclaimer**: this is intended for simple apps or for when you're just starting out building an app. More complex apps will require more code in their controllers and should use standard Phoenix controllers and tests. This is just a starting point. |
| 12 | + **Disclaimer**: This is intended for simple apps or when starting to build an application. More complex apps may require more complexity in their controllers, and then a standard Phoenix controller with tests would work better. This is just a starting point. |
| 13 13 | |
| 14 14 | ## Installation |
| 15 15 | |
| @@ -28,8 +28,7 @@ Add `use Transponder` to your controllers, and define actions with `defaction`: | |
| 28 28 | ```elixir |
| 29 29 | defmodule MyAppWeb.Admin.ProductsController do |
| 30 30 | use MyAppWeb, :controller |
| 31 | - use Transponder, |
| 32 | - responder: Transponder.Responders.JSON |
| 31 | + use Transponder, format: Transponder.JSON |
| 33 32 | |
| 34 33 | defaction :index, &Catalog.list_products(&1.params) |
| 35 34 | defaction :show, &Catalog.get_product(&1.params) |
| @@ -45,11 +44,11 @@ Then define a `show.json.eex` and `index.json.eex`. Or you can use a `Phoenix.Vi | |
| 45 44 | defmodule MyAppWeb.Admin.ProductsView do |
| 46 45 | use MyAppWeb, :view |
| 47 46 | |
| 48 | - def render("index.json", %{response: products}) do |
| 47 | + def render("index.json", %{records: products}) do |
| 49 48 | %{products: Enum.map(&render("show.json", response: &1))} |
| 50 49 | end |
| 51 50 | |
| 52 | - def render("show.json", %{response: product}) do |
| 51 | + def render("show.json", %{record: product}) do |
| 53 52 | %{ |
| 54 53 | id: product.id, |
| 55 54 | title: product.title, |
| @@ -59,13 +58,18 @@ defmodule MyAppWeb.Admin.ProductsView do | |
| 59 58 | end |
| 60 59 | ``` |
| 61 60 | |
| 62 | - To render HTML instead of JSON use `Responders.HTML`: |
| 61 | + To handle errors, configure the error view in `config/config.exs`: |
| 62 | + |
| 63 | + ```elixir |
| 64 | + config :transponder, :error_view, MyAppWeb.ErrorView |
| 65 | + ``` |
| 66 | + |
| 67 | + To render HTML instead of JSON use `Transponder.HTML`: |
| 63 68 | |
| 64 69 | ```elixir |
| 65 70 | defmodule MayAppWeb.Admin.ProductController do |
| 66 71 | use MyAppWeb, :controller |
| 67 | - use Transponder, |
| 68 | - responder: Transponder.Responders.HTML |
| 72 | + use Transponder, format: Transponder.HTML |
| 69 73 | |
| 70 74 | # defaction ... |
| 71 75 | end |
| @@ -73,21 +77,21 @@ end | |
| 73 77 | |
| 74 78 | And then you'll need to create templates for the actions you use: `index.html.eex`, `show.html.eex`, etc.. |
| 75 79 | |
| 76 | - You can also create a custom responder: |
| 80 | + You can also create a custom formatter: |
| 77 81 | |
| 78 82 | ```elixir |
| 79 | - defmodule MyResponder do |
| 80 | - @behaviour Transponder.Responder |
| 83 | + defmodule MyFormat do |
| 84 | + @behaviour Transponder.Formatter |
| 81 85 | |
| 82 86 | # pattern match and render how you like |
| 83 87 | @impl true |
| 84 | - def respond(_action, conn, {:ok, bla}) do |
| 88 | + def format(_action, conn, {:ok, bla}) do |
| 85 89 | conn |
| 86 90 | |> put_status(200) |
| 87 91 | |> render("yay.html") |
| 88 92 | end |
| 89 93 | |
| 90 | - def respond(_action, conn, {:error, bla}) do |
| 94 | + def format(_action, conn, {:error, bla}) do |
| 91 95 | conn |
| 92 96 | |> put_status(401) |
| 93 97 | |> render("oops.html") |
| @@ -4,7 +4,7 @@ | |
| 4 4 | {<<"elixir">>,<<"~> 1.9">>}. |
| 5 5 | {<<"files">>, |
| 6 6 | [<<"lib">>,<<"lib/transponder">>,<<"lib/transponder/html.ex">>, |
| 7 | - <<"lib/transponder/responder.ex">>,<<"lib/transponder/json.ex">>, |
| 7 | + <<"lib/transponder/formatter.ex">>,<<"lib/transponder/json.ex">>, |
| 8 8 | <<"lib/transponder.ex">>,<<".formatter.exs">>,<<"mix.exs">>, |
| 9 9 | <<"README.md">>]}. |
| 10 10 | {<<"licenses">>,[<<"MIT">>]}. |
| @@ -31,4 +31,4 @@ | |
| 31 31 | {<<"optional">>,false}, |
| 32 32 | {<<"repository">>,<<"hexpm">>}, |
| 33 33 | {<<"requirement">>,<<"~> 1.2">>}]]}. |
| 34 | - {<<"version">>,<<"0.1.0">>}. |
| 34 | + {<<"version">>,<<"0.1.1">>}. |
| @@ -4,12 +4,12 @@ defmodule Transponder do | |
| 4 4 | """ |
| 5 5 | |
| 6 6 | defmacro __using__(opts) do |
| 7 | - responder = Keyword.fetch!(opts, :responder) |
| 7 | + format = Keyword.fetch!(opts, :format) |
| 8 8 | |
| 9 9 | quote do |
| 10 10 | import Transponder |
| 11 11 | |
| 12 | - @responder unquote(responder) |
| 12 | + @formatter unquote(format) |
| 13 13 | end |
| 14 14 | end |
| 15 15 | |
| @@ -17,7 +17,7 @@ defmodule Transponder do | |
| 17 17 | quote do |
| 18 18 | def unquote(name)(conn, params) do |
| 19 19 | data = %{conn: conn, params: params, assigns: conn.assigns} |
| 20 | - @responder.respond(unquote(name), conn, unquote(fun).(data)) |
| 20 | + @formatter.format(unquote(name), conn, unquote(fun).(data)) |
| 21 21 | end |
| 22 22 | end |
| 23 23 | end |
| @@ -0,0 +1,3 @@ | |
| 1 | + defmodule Transponder.Formatter do |
| 2 | + @callback format(atom, Plug.Conn.t(), term) :: Plug.Conn.t() |
| 3 | + end |
| @@ -1,65 +1,67 @@ | |
| 1 1 | defmodule Transponder.HTML do |
| 2 | - @behaviour Transponder.Responder |
| 2 | + @behaviour Transponder.Formatter |
| 3 3 | |
| 4 4 | import Plug.Conn |
| 5 5 | import Phoenix.Controller |
| 6 6 | |
| 7 7 | @impl true |
| 8 | - def respond(_action, conn, {:error, :not_found}) do |
| 8 | + def format(_action, conn, {:error, :not_found}) do |
| 9 9 | conn |
| 10 10 | |> put_status(:not_found) |
| 11 11 | |> render("404.html") |
| 12 12 | end |
| 13 13 | |
| 14 | - def respond(:new, conn, {:ok, record}) do |
| 14 | + def format(:new, conn, {:ok, record}) do |
| 15 15 | render(conn, "new.html", record: record) |
| 16 16 | end |
| 17 17 | |
| 18 | - def respond(:create, conn, {:error, changeset = %Ecto.Changeset{}}) do |
| 18 | + def format(:create, conn, {:error, changeset = %Ecto.Changeset{}}) do |
| 19 19 | conn |
| 20 20 | |> put_status(:unprocessable_entity) |
| 21 21 | |> render("new.html", record: changeset.data, changeset: changeset) |
| 22 22 | end |
| 23 23 | |
| 24 | - def respond(:create, conn, {:ok, _record}) do |
| 24 | + def format(:create, conn, {:ok, _record}) do |
| 25 25 | conn |
| 26 26 | |> put_flash(:info, "Created") |
| 27 27 | |> redirect(to: "/") |
| 28 28 | end |
| 29 29 | |
| 30 | - def respond(:edit, conn, {:ok, record}) do |
| 30 | + def format(:edit, conn, {:ok, record}) do |
| 31 31 | render(conn, "edit.html", record: record) |
| 32 32 | end |
| 33 33 | |
| 34 | - def respond(:update, conn, {:error, changeset}) do |
| 34 | + def format(:update, conn, {:error, changeset}) do |
| 35 35 | conn |
| 36 36 | |> put_status(:unprocessable_entity) |
| 37 37 | |> render("edit.html", record: changeset.data, changeset: changeset) |
| 38 38 | end |
| 39 39 | |
| 40 | - def respond(:update, conn, {:ok, _record}) do |
| 40 | + def format(:update, conn, {:ok, _record}) do |
| 41 41 | conn |
| 42 42 | |> put_flash(:info, "Updated") |
| 43 43 | |> redirect(to: "/") |
| 44 44 | end |
| 45 45 | |
| 46 | - def respond(:index, conn, {:ok, records}) do |
| 46 | + def format(:index, conn, {:ok, records}) do |
| 47 47 | render(conn, "index.html", records: records) |
| 48 48 | end |
| 49 49 | |
| 50 | - def respond(:show, conn, {:ok, record}) do |
| 50 | + def format(:show, conn, {:ok, record}) do |
| 51 51 | render(conn, "show.html", record: record) |
| 52 52 | end |
| 53 53 | |
| 54 | - def respond(:delete, conn, {:ok, _record}) do |
| 54 | + def format(:delete, conn, {:ok, _record}) do |
| 55 55 | conn |
| 56 56 | |> put_flash(:info, "Deleted") |
| 57 57 | |> redirect(to: "/") |
| 58 58 | end |
| 59 59 | |
| 60 | - def respond(_action, conn, _response) do |
| 61 | - conn |
| 62 | - |> put_status(500) |
| 63 | - |> render("500.html") |
| 60 | + if Mix.env() != :dev do |
| 61 | + def format(_action, conn, _response) do |
| 62 | + conn |
| 63 | + |> put_status(500) |
| 64 | + |> render("500.html") |
| 65 | + end |
| 64 66 | end |
| 65 67 | end |
Loading more files…