Add HTTP wrap func and Text Encodable:

- Refactor HTTP send func
- Impl. Text Encodable for URL
- Error when url is not found
This commit is contained in:
mitchell 2020-01-01 18:11:38 -05:00
parent b699e661e2
commit 1502d10cdc
8 changed files with 84 additions and 41 deletions

View file

@ -3,13 +3,20 @@ defmodule Shortnr.Transport.HTTP do
This module contains functions that can be used to handle HTTP requests and send responses, by
manipulating Plug.Conn.
"""
alias Shortnr.Transport
import Plug.Conn
@type error :: {:error, {atom(), String.t()}, Plug.Conn.t()}
@type ok_error :: {:ok, term(), Plug.Conn.t()} | error()
@spec handle(ok_error(), (... -> ok_error())) :: ok_error()
@spec wrap(Plug.Conn.t(), term()) :: ok_error
def wrap(conn, argument \\ nil)
def wrap(conn, nil), do: {:ok, nil, conn}
def wrap(conn, {first, _second} = argument) when is_atom(first), do: {:error, argument, conn}
def wrap(conn, argument), do: {:ok, argument, conn}
@spec handle(ok_error(), (term() -> Transport.ok_error()) | (() -> Transport.ok_error())) ::
ok_error()
def handle(error = {:error, _sub_error, _conn}, _func), do: error
def handle({:ok, request, conn}, func) when is_function(func, 1) do
@ -29,19 +36,24 @@ defmodule Shortnr.Transport.HTTP do
defp convert_error({:invalid_argument, message}, conn),
do: {:error, {:bad_request, message}, conn}
defp convert_error({:not_found, message}, conn),
do: {:error, {:not_found, message}, conn}
defp convert_error(_, conn), do: {:error, {:internal_server_error, "unknown error"}, conn}
@spec send(ok_error(), atom(), Plug.Conn.t()) :: Plug.Conn.t()
def send({:error, {status, body}, _conn}, _success_status, original_conn) do
send_resp(original_conn, status_to_code(status), body)
@spec send(ok_error(), atom()) :: Plug.Conn.t()
def send(ok_error, success_status \\ nil)
def send({:error, {status, body}, conn}, _success_status) do
send_resp(conn, status_to_code(status), body)
end
def send({:ok, body, conn}, :found, _original_conn) do
conn = put_resp_header(conn, "Location", URI.to_string(body))
send_resp(conn, status_to_code(:found), URI.to_string(body))
def send({:ok, location, conn}, :found) do
conn = put_resp_header(conn, "Location", location)
send_resp(conn, status_to_code(:found), location)
end
def send({:ok, body, conn}, success_status, _original_conn) do
def send({:ok, body, conn}, success_status) do
send_resp(conn, status_to_code(success_status), body)
end

View file

@ -5,7 +5,7 @@ defmodule Shortnr.Transport.Text do
import Plug.Conn
alias Shortnr.Transport.HTTP
alias Shortnr.URL
alias Shortnr.Transport.Text.Encodable
@spec decode_request(Plug.Conn.t()) :: HTTP.ok_error()
def decode_request(conn) do
@ -24,11 +24,20 @@ defmodule Shortnr.Transport.Text do
{:ok, for(item <- body, into: "", do: "#{item}\n"), conn}
end
def encode_response({:ok, %URL{url: url}, conn}) do
{:ok, url, conn}
end
def encode_response({:ok, body, conn}) do
{:ok, "#{body}", conn}
{:ok, Encodable.encode(body), conn}
end
end
defprotocol Shortnr.Transport.Text.Encodable do
@moduledoc """
Implement this protocol for your type if you would like to text encode it.
"""
@fallback_to_any true
def encode(encodable)
end
defimpl Shortnr.Transport.Text.Encodable, for: Any do
def encode(encodable), do: to_string(encodable)
end