diff --git a/CHANGELOG.org b/CHANGELOG.org index 08ba912..da26e62 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -17,4 +17,6 @@ Added the simple index page. ** 0.3.2 <2023-07-09 Sun> Added the simple dev configuration. +** 0.4.0 <2023-07-28 Fri> + Added the API to show the Links model or models. diff --git a/lib/link_shortener_web/controllers/api/v1/links_controller.ex b/lib/link_shortener_web/controllers/api/v1/links_controller.ex new file mode 100644 index 0000000..6fa0a72 --- /dev/null +++ b/lib/link_shortener_web/controllers/api/v1/links_controller.ex @@ -0,0 +1,17 @@ +defmodule LinkShortenerWeb.Api.V1.LinksController do + use LinkShortenerWeb, :controller + + alias LinkShortener.Links + + action_fallback LinkShortenerWeb.FallbackController + + def index(conn, _params) do + links = Links.get_all({}) + render(conn, "index.json", links: links) + end + + def show(conn, %{"id" => id}) do + link = Links.get_one(id) + render(conn, "show.json", links: link) + end +end diff --git a/lib/link_shortener_web/controllers/fallback_controller.ex b/lib/link_shortener_web/controllers/fallback_controller.ex new file mode 100644 index 0000000..5f25eb5 --- /dev/null +++ b/lib/link_shortener_web/controllers/fallback_controller.ex @@ -0,0 +1,24 @@ +defmodule LinkShortenerWeb.FallbackController do + @moduledoc """ + Translates controller action results into valid `Plug.Conn` responses. + + See `Phoenix.Controller.action_fallback/1` for more details. + """ + use LinkShortenerWeb, :controller + + # This clause handles errors returned by Ecto's insert/update/delete. + def call(conn, {:error, %Ecto.Changeset{} = changeset}) do + conn + |> put_status(:unprocessable_entity) + |> put_view(LinkShortenerWeb.ChangesetView) + |> render("error.json", changeset: changeset) + end + + # This clause is an example of how to handle resources that cannot be found. + def call(conn, {:error, :not_found}) do + conn + |> put_status(:not_found) + |> put_view(LinkShortenerWeb.ErrorView) + |> render(:"404") + end +end diff --git a/lib/link_shortener_web/router.ex b/lib/link_shortener_web/router.ex index a60be5d..7e0deca 100644 --- a/lib/link_shortener_web/router.ex +++ b/lib/link_shortener_web/router.ex @@ -22,9 +22,13 @@ defmodule LinkShortenerWeb.Router do end # Other scopes may use custom stacks. - # scope "/api", LinkShortenerWeb do - # pipe_through :api - # end + scope "/api", LinkShortenerWeb do + pipe_through :api + + scope "/v1", Api.V1, as: :v1 do + resources "/links", LinksController, except: [:new, :edit] + end + end # Enables LiveDashboard only for development # diff --git a/lib/link_shortener_web/views/api/v1/links_view.ex b/lib/link_shortener_web/views/api/v1/links_view.ex new file mode 100644 index 0000000..86df33e --- /dev/null +++ b/lib/link_shortener_web/views/api/v1/links_view.ex @@ -0,0 +1,21 @@ +defmodule LinkShortenerWeb.Api.V1.LinksView do + use LinkShortenerWeb, :view + alias LinkShortenerWeb.Api.V1.LinksView + + def render("index.json", %{links: links}) do + %{data: render_many(links, LinksView, "link.json")} + end + + def render("show.json", %{links: link}) do + %{data: render_one(link, LinksView, "link.json")} + end + + def render("link.json", %{links: link}) do + %{ + id: link.id, + name: link.name, + url: link.url, + shorten: link.shorten + } + end +end diff --git a/lib/link_shortener_web/views/changeset_view.ex b/lib/link_shortener_web/views/changeset_view.ex new file mode 100644 index 0000000..594018b --- /dev/null +++ b/lib/link_shortener_web/views/changeset_view.ex @@ -0,0 +1,19 @@ +defmodule LinkShortenerWeb.ChangesetView do + use LinkShortenerWeb, :view + + @doc """ + Traverses and translates changeset errors. + + See `Ecto.Changeset.traverse_errors/2` and + `LinkShortenerWeb.ErrorHelpers.translate_error/1` for more details. + """ + def translate_errors(changeset) do + Ecto.Changeset.traverse_errors(changeset, &translate_error/1) + end + + def render("error.json", %{changeset: changeset}) do + # When encoded, the changeset returns its errors + # as a JSON object. So we just pass it forward. + %{errors: translate_errors(changeset)} + end +end