diff options
author | William Carroll <wpcarro@gmail.com> | 2020-12-12T02·43+0000 |
---|---|---|
committer | William Carroll <wpcarro@gmail.com> | 2020-12-12T02·43+0000 |
commit | 8c5e4e77edacf082b5ab2d8aede49aa0ddfb9b5e (patch) | |
tree | b216303b8755d7d945a35a2a3d12d77b3828ceeb /assessments/semiprimes/server/lib | |
parent | 45877a8b9cbe728e2dd66c361b3d6625810b31a0 (diff) |
Expose functions at API layer
Creating a simple HTTP RESTful API for exposing our `Server.semiprime` function. It supports some help messages, primitive parsing and error handling, and singular vs. batch processing of arguments. For more sophisticated parsing and error-checking, I prefer to use Haskell's Servant library.
Diffstat (limited to 'assessments/semiprimes/server/lib')
-rw-r--r-- | assessments/semiprimes/server/lib/router.ex | 86 | ||||
-rw-r--r-- | assessments/semiprimes/server/lib/sup.ex | 4 |
2 files changed, 89 insertions, 1 deletions
diff --git a/assessments/semiprimes/server/lib/router.ex b/assessments/semiprimes/server/lib/router.ex new file mode 100644 index 000000000000..cb55520920de --- /dev/null +++ b/assessments/semiprimes/server/lib/router.ex @@ -0,0 +1,86 @@ +defmodule Router do + use Plug.Router + use Plug.Debugger + require Logger + + plug(Plug.Logger, log: :debug) + plug(Plug.Parsers, parsers: [:urlencoded]) + plug(:match) + plug(:dispatch) + + @usage """ + Usage: Try querying some of the following endpoints... + GET / + GET /help + GET /semiprime?number=<integer> + GET /semiprimes?numbers=<comma-separated-integers> + """ + + get "/" do + send_resp(conn, 200, "Welcome to Semiprimes Service!\n\n#{@usage}") + end + + get "/help" do + send_resp(conn, 200, @usage) + end + + get "/semiprime" do + case conn |> Map.get(:query_params) |> Map.get("number") do + nil -> + send_resp(conn, 400, "You must pass an integer as a query parameter. #{@usage}") + + val -> + case Integer.parse(val) do + {n, ""} -> + send_resp(conn, 200, semiprime_response(n)) + + _ -> + send_resp(conn, 400, "We could not parse the number you provided.\n\n#{@usage}") + end + end + end + + get "/semiprimes" do + case conn |> Map.get(:query_params) |> Map.get("numbers") do + nil -> + send_resp( + conn, + 400, + "You must pass a comma-separated list of integers as a query parameter.\n\n#{@usage}" + ) + + xs -> + response = + xs + |> String.split(",") + |> Stream.map(&Integer.parse/1) + |> Stream.filter(fn + {n, ""} -> true + _ -> false + end) + |> Stream.map(fn {n, ""} -> semiprime_response(n) end) + |> Enum.join("\n") + + send_resp(conn, 200, response) + end + end + + match _ do + send_resp(conn, 404, "Not found.") + end + + ################################################################################ + # Utils + ################################################################################ + + defp semiprime_response(n) do + case Server.semiprime(n) do + nil -> + "#{n} is not a semiprime. Try another number!" + + {hit_or_miss, factors} -> + response = "#{n} is a semiprime! Its factors are #{Enum.join(factors, " and ")}." + "Cache #{Atom.to_string(hit_or_miss)} - #{response}" + end + end +end diff --git a/assessments/semiprimes/server/lib/sup.ex b/assessments/semiprimes/server/lib/sup.ex index ea02ce30e7b9..13a6ab374ff6 100644 --- a/assessments/semiprimes/server/lib/sup.ex +++ b/assessments/semiprimes/server/lib/sup.ex @@ -5,6 +5,7 @@ defmodule Sup do """ use Supervisor + alias Plug.Adapters.Cowboy def start_link(opts \\ []) do Supervisor.start_link(__MODULE__, :ok, opts) @@ -13,7 +14,8 @@ defmodule Sup do @impl true def init(:ok) do children = [ - Cache + Cache, + Cowboy.child_spec(scheme: :http, plug: Router, options: [port: 8000]) ] Supervisor.init(children, strategy: :one_for_one) |