diff --git a/lib/app/item.ex b/lib/app/item.ex index 79944197..71d6cb7b 100644 --- a/lib/app/item.ex +++ b/lib/app/item.ex @@ -6,6 +6,7 @@ defmodule App.Item do alias __MODULE__ require Logger + @derive {Jason.Encoder, only: [:id, :person_id, :status, :text]} schema "items" do field :person_id, :integer field :status, :integer diff --git a/lib/app_web/controllers/api/item_controller.ex b/lib/app_web/controllers/api/item_controller.ex new file mode 100644 index 00000000..3808c3cd --- /dev/null +++ b/lib/app_web/controllers/api/item_controller.ex @@ -0,0 +1,93 @@ +defmodule AppWeb.API.ItemController do + use AppWeb, :controller + alias App.Item + import Ecto.Changeset + + def show(conn, params) do + id = Map.get(params, "id") + + try do + item = Item.get_item!(id) + json(conn, item) + rescue + Ecto.NoResultsError -> + errors = %{ + code: 404, + message: "No item found with the given \'id\'.", + } + json(conn |> put_status(404), errors) + + Ecto.Query.CastError -> + errors = %{ + code: 400, + message: "The \'id\' is not an integer.", + } + json(conn |> put_status(400), errors) + end + end + + def create(conn, params) do + # Attributes to create item + # Person_id will be changed when auth is added + attrs = %{ + text: Map.get(params, "text"), + person_id: 0, + status: 2 + } + + case Item.create_item(attrs) do + + # Successfully creates item + {:ok, item} -> + id_item = Map.take(item, [:id]) + json(conn, id_item) + + # Error creating item + {:error, %Ecto.Changeset{} = changeset} -> + errors = make_changeset_errors_readable(changeset) + + json( + conn |> put_status(400), + errors + ) + end + end + + def update(conn, params) do + id = Map.get(params, "id") + new_text = Map.get(params, "text") + + item = Item.get_item!(id) + + case Item.update_item(item, %{text: new_text}) do + + # Successfully updates item + {:ok, item} -> + json(conn, item) + + # Error creating item + {:error, %Ecto.Changeset{} = changeset} -> + errors = make_changeset_errors_readable(changeset) + + json( + conn |> put_status(400), + errors + ) + end + end + + defp make_changeset_errors_readable(changeset) do + errors = %{ + code: 400, + message: "Malformed request", + } + + changeset_errors = traverse_errors(changeset, fn {msg, opts} -> + Regex.replace(~r"%{(\w+)}", msg, fn _, key -> + opts |> Keyword.get(String.to_existing_atom(key), key) |> to_string() + end) + end) + + Map.put(errors, :errors, changeset_errors) + end +end diff --git a/lib/app_web/router.ex b/lib/app_web/router.ex index 62b88847..968cbaf1 100644 --- a/lib/app_web/router.ex +++ b/lib/app_web/router.ex @@ -10,6 +10,10 @@ defmodule AppWeb.Router do plug :put_secure_browser_headers end + pipeline :api do + plug :accepts, ["json"] + end + # No Auth scope "/", AppWeb do pipe_through :browser @@ -17,7 +21,10 @@ defmodule AppWeb.Router do get "/login", AuthController, :login end - pipeline :authOptional, do: plug(AuthPlugOptional) + pipeline :authOptional do + plug :fetch_session + plug(AuthPlugOptional) + end scope "/", AppWeb do pipe_through [:browser, :authOptional] @@ -26,4 +33,10 @@ defmodule AppWeb.Router do live "/stats", StatsLive resources "/tags", TagController, except: [:show] end + + scope "/api", AppWeb do + pipe_through [:api, :authOptional] + + resources "/items", API.ItemController, only: [:create, :update, :show] + end end