mirror of https://github.com/mitchell/shortnr.git
Add Endpoints behaviour and refactor router and related methods
This commit is contained in:
parent
1502d10cdc
commit
98684feb2d
|
@ -0,0 +1,11 @@
|
|||
:0: Unknown function 'Elixir.Shortnr.Transport.Text.Encodable.Atom':'__impl__'/1
|
||||
:0: Unknown function 'Elixir.Shortnr.Transport.Text.Encodable.BitString':'__impl__'/1
|
||||
:0: Unknown function 'Elixir.Shortnr.Transport.Text.Encodable.Float':'__impl__'/1
|
||||
:0: Unknown function 'Elixir.Shortnr.Transport.Text.Encodable.Function':'__impl__'/1
|
||||
:0: Unknown function 'Elixir.Shortnr.Transport.Text.Encodable.Integer':'__impl__'/1
|
||||
:0: Unknown function 'Elixir.Shortnr.Transport.Text.Encodable.List':'__impl__'/1
|
||||
:0: Unknown function 'Elixir.Shortnr.Transport.Text.Encodable.Map':'__impl__'/1
|
||||
:0: Unknown function 'Elixir.Shortnr.Transport.Text.Encodable.PID':'__impl__'/1
|
||||
:0: Unknown function 'Elixir.Shortnr.Transport.Text.Encodable.Port':'__impl__'/1
|
||||
:0: Unknown function 'Elixir.Shortnr.Transport.Text.Encodable.Reference':'__impl__'/1
|
||||
:0: Unknown function 'Elixir.Shortnr.Transport.Text.Encodable.Tuple':'__impl__'/1
|
|
@ -3,57 +3,27 @@ defmodule Shortnr.Router do
|
|||
This module contains the Router for the Shortnr application. Do not import, other than
|
||||
Application entry.
|
||||
"""
|
||||
use Plug.ErrorHandler
|
||||
use Plug.Router
|
||||
alias Shortnr.Transport.HTTP
|
||||
alias Shortnr.URL
|
||||
|
||||
require Logger
|
||||
|
||||
alias Shortnr.Transport.{HTTP, Text}
|
||||
alias Shortnr.URL
|
||||
use Plug.ErrorHandler
|
||||
use Plug.Router
|
||||
|
||||
plug(Plug.Logger, log: :debug)
|
||||
plug(:match)
|
||||
plug(:dispatch)
|
||||
|
||||
get "/" do
|
||||
conn
|
||||
|> HTTP.wrap()
|
||||
|> HTTP.handle(fn -> URL.list(URL.Repo.ETS) end)
|
||||
|> Text.encode_response()
|
||||
|> HTTP.send(:ok)
|
||||
end
|
||||
# BEGIN URL routes
|
||||
post("/urls/:url", do: URL.Endpoints.select(conn, :create, url))
|
||||
|
||||
post "/urls/:url" do
|
||||
conn
|
||||
|> HTTP.wrap(url)
|
||||
|> HTTP.handle(&URL.create(&1, URL.Repo.ETS))
|
||||
|> Text.encode_response()
|
||||
|> HTTP.send(:created)
|
||||
end
|
||||
get("/", do: URL.Endpoints.select(conn, :list))
|
||||
get("/urls", do: URL.Endpoints.select(conn, :list))
|
||||
get("/:id", do: URL.Endpoints.select(conn, :get, id))
|
||||
|
||||
get "/urls" do
|
||||
conn
|
||||
|> HTTP.wrap()
|
||||
|> HTTP.handle(fn -> URL.list(URL.Repo.ETS) end)
|
||||
|> Text.encode_response()
|
||||
|> HTTP.send(:ok)
|
||||
end
|
||||
|
||||
get "/:id" do
|
||||
conn
|
||||
|> HTTP.wrap(id)
|
||||
|> HTTP.handle(&URL.get(&1, URL.Repo.ETS))
|
||||
|> Text.encode_response()
|
||||
|> HTTP.send(:found)
|
||||
end
|
||||
|
||||
delete "/:id" do
|
||||
conn
|
||||
|> HTTP.wrap(id)
|
||||
|> HTTP.handle(&URL.delete(&1, URL.Repo.ETS))
|
||||
|> Text.encode_response()
|
||||
|> HTTP.send(:ok)
|
||||
end
|
||||
delete("/:id", do: URL.Endpoints.select(conn, :delete, id))
|
||||
# END
|
||||
|
||||
match _ do
|
||||
conn
|
||||
|
|
|
@ -3,15 +3,13 @@ defmodule Shortnr do
|
|||
The Shortnr application entry point. Check README for usage documenation.
|
||||
"""
|
||||
|
||||
use Application
|
||||
require Logger
|
||||
use Application
|
||||
|
||||
@impl true
|
||||
@impl Application
|
||||
def start(_type, _args) do
|
||||
port = port()
|
||||
|
||||
children = [
|
||||
{Plug.Cowboy, scheme: :http, plug: Shortnr.Router, options: [port: port]}
|
||||
{Plug.Cowboy, scheme: :http, plug: Shortnr.Router, options: [port: port()]}
|
||||
]
|
||||
|
||||
if ets_implementation() == :dets do
|
||||
|
@ -20,11 +18,11 @@ defmodule Shortnr do
|
|||
:ets.new(:urls, [:set, :named_table])
|
||||
end
|
||||
|
||||
Logger.info("server starting", port: port)
|
||||
Logger.info("server starting", port: port())
|
||||
Supervisor.start_link(children, strategy: :one_for_one)
|
||||
end
|
||||
|
||||
@impl true
|
||||
@impl Application
|
||||
def stop(_state) do
|
||||
if ets_implementation() == :dets, do: :dets.close(:urls)
|
||||
end
|
||||
|
|
|
@ -64,3 +64,12 @@ defmodule Shortnr.Transport.HTTP do
|
|||
defp status_to_code(:not_found), do: 404
|
||||
defp status_to_code(:internal_server_error), do: 500
|
||||
end
|
||||
|
||||
defmodule Shortnr.Transport.HTTP.Endpoints do
|
||||
@moduledoc """
|
||||
This modules is a behaviour that should be implemented by each service that needs to be routed by
|
||||
Plug.Router
|
||||
"""
|
||||
|
||||
@callback select(Plug.Conn.t(), atom, term) :: Plug.Conn.t()
|
||||
end
|
||||
|
|
|
@ -3,28 +3,29 @@ defmodule Shortnr.Transport.Text do
|
|||
This modules contains functions to decode and encode text formatted http requests and responses.
|
||||
"""
|
||||
|
||||
import Plug.Conn
|
||||
alias Shortnr.Transport.HTTP
|
||||
alias Shortnr.Transport.Text.Encodable
|
||||
|
||||
@spec decode_request(Plug.Conn.t()) :: HTTP.ok_error()
|
||||
def decode_request(conn) do
|
||||
import Plug.Conn
|
||||
|
||||
@spec decode(HTTP.ok_error()) :: HTTP.ok_error()
|
||||
def decode({:ok, _body, conn}) do
|
||||
{:ok, body, conn} = read_body(conn)
|
||||
{:ok, body, conn}
|
||||
end
|
||||
|
||||
@spec encode_response(HTTP.ok_error()) :: HTTP.ok_error()
|
||||
def encode_response(ok_error = {:error, _, _}), do: ok_error
|
||||
@spec encode(HTTP.ok_error()) :: HTTP.ok_error()
|
||||
def encode(ok_error = {:error, _, _}), do: ok_error
|
||||
|
||||
def encode_response({:ok, [], conn}) do
|
||||
def encode({:ok, [], conn}) do
|
||||
{:ok, "", conn}
|
||||
end
|
||||
|
||||
def encode_response({:ok, body, conn}) when is_list(body) do
|
||||
def encode({:ok, body, conn}) when is_list(body) do
|
||||
{:ok, for(item <- body, into: "", do: "#{item}\n"), conn}
|
||||
end
|
||||
|
||||
def encode_response({:ok, body, conn}) do
|
||||
def encode({:ok, body, conn}) do
|
||||
{:ok, Encodable.encode(body), conn}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
defmodule Shortnr.URL.Endpoints do
|
||||
@moduledoc """
|
||||
This module implements the Endpoints behaviour.
|
||||
"""
|
||||
alias Shortnr.Transport.{HTTP, Text}
|
||||
alias Shortnr.Transport.HTTP.Endpoints
|
||||
alias Shortnr.URL
|
||||
|
||||
@behaviour Endpoints
|
||||
|
||||
@impl Endpoints
|
||||
def select(conn, name, arg \\ nil)
|
||||
|
||||
def select(conn, :list, _arg) do
|
||||
conn
|
||||
|> HTTP.wrap()
|
||||
|> HTTP.handle(fn -> URL.list(URL.Repo.ETS) end)
|
||||
|> Text.encode()
|
||||
|> HTTP.send(:ok)
|
||||
end
|
||||
|
||||
def select(conn, :create, url) do
|
||||
conn
|
||||
|> HTTP.wrap(url)
|
||||
|> HTTP.handle(&URL.create(&1, URL.Repo.ETS))
|
||||
|> Text.encode()
|
||||
|> HTTP.send(:created)
|
||||
end
|
||||
|
||||
def select(conn, :get, id) do
|
||||
conn
|
||||
|> HTTP.wrap(id)
|
||||
|> HTTP.handle(&URL.get(&1, URL.Repo.ETS))
|
||||
|> Text.encode()
|
||||
|> HTTP.send(:found)
|
||||
end
|
||||
|
||||
def select(conn, :delete, id) do
|
||||
conn
|
||||
|> HTTP.wrap(id)
|
||||
|> HTTP.handle(&URL.delete(&1, URL.Repo.ETS))
|
||||
|> Text.encode()
|
||||
|> HTTP.send(:ok)
|
||||
end
|
||||
end
|
|
@ -2,10 +2,11 @@ defmodule Shortnr.URL.Repo.ETS do
|
|||
@moduledoc """
|
||||
This module is an implemention of the Repo behaviour using the Erlang ETS library.
|
||||
"""
|
||||
alias Shortnr.URL.Repo
|
||||
|
||||
@behaviour Shortnr.URL.Repo
|
||||
@behaviour Repo
|
||||
|
||||
@impl true
|
||||
@impl Repo
|
||||
def get(key) do
|
||||
case ets().lookup(:urls, key) |> List.first() do
|
||||
{_, url} -> {:ok, url}
|
||||
|
@ -13,25 +14,25 @@ defmodule Shortnr.URL.Repo.ETS do
|
|||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
@impl Repo
|
||||
def put(url) do
|
||||
:ok = ets().insert(:urls, {url.id, url})
|
||||
:ok
|
||||
end
|
||||
|
||||
@impl true
|
||||
@impl Repo
|
||||
def list do
|
||||
resp = ets().select(:urls, [{:"$1", [], [:"$1"]}])
|
||||
{:ok, resp |> Enum.map(&elem(&1, 1))}
|
||||
end
|
||||
|
||||
@impl true
|
||||
@impl Repo
|
||||
def delete(key) do
|
||||
:ok = ets().delete(:urls, key)
|
||||
:ok
|
||||
end
|
||||
|
||||
@impl true
|
||||
@impl Repo
|
||||
def reset do
|
||||
:ok = ets().delete_all_objects(:urls)
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue