cat-bookmarker/lib/bookmarker_web/router.ex

159 lines
5.3 KiB
Elixir

defmodule BookmarkerWeb.Router do
use BookmarkerWeb, :router
@doc """
A quicker way to return a JSON object with the key "error" and the given
message
"""
defp error(conn, message) do
json(conn, %{"error" => message})
end
@doc """
Checks to see if the request includes an Authorization header. If it does,
then the value of the header is put into a more convenient place in the
`conn` object. Otherwise, the server returns a client error.
"""
defp has_authorization(conn, _params) do
# Fail if the user hasn't included the authorization header
case get_req_header(conn, "authorization") do
[auth] -> assign(conn, :auth, auth)
_ -> conn
|> put_status(401)
|> error("Unauthorized")
end
end
@doc """
Checks that the Authorization style is basic. More generally, ensures that
the header isn't malformatted. If it is, then the server complains that the
client is unauthorized. If not, then the user ID gets extracted from the
header and passed down the line.
"""
defp authorization_is_basic(conn, _params) do
case String.split(conn.assigns[:auth]) do
["Basic", id] -> assign(conn, :user_id, id)
# In this case, the header value doesn't fit the "Basic 123..."
# pattern and the server returns 401
_ -> conn
|> put_status(401)
|> error("Authorization must be Basic")
end
end
@doc """
Attempts to parse the user ID as an integer. If it can't do that, then
the Authorization header's value is malformed and a 401 error code is
returned. Otherwise, the :user_id key gets reassigned to the parsed integer
for later use
"""
defp credential_is_integer(conn, _params) do
case Integer.parse(conn.assigns.user_id) do
{id, _} ->
# Replace the :user_id with the parsed integer
conn
|> assign(:user_id, id)
:error -> conn
|> put_status(401)
|> error("Malformed Authorization credentials")
end
end
# Pipelines are a series of plugs. Plugs make changes to the connection
# before passing them on.
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :put_root_layout, {BookmarkerWeb.LayoutView, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers
end
# This pipeline, used for the API, ensures that the request has an
# Authorization header, ensures that the Authorization style is "Basic,"
# and then ensures that the credentials are just an integer. It then parses
# the request body as JSON so that it can be easily accessed later from the
# controllers.
pipeline :api do
plug :accepts, ["json"]
plug :has_authorization
plug :authorization_is_basic
plug :credential_is_integer
plug Plug.Parsers,
parsers: [:json],
json_decoder: {Jason, :decode!, [[floats: :decimals]]}
end
# Generates a semi-private page for the user to navigate to.
scope "/", BookmarkerWeb do
pipe_through :browser
get "/", AppController, :index
# On the front end, this is a single-page app. So, if you were to,
# say, bookmark your ID in the browser and navigate to it, Phoenix
# would get confused. This controller will pass the given ID to
# the home route as a query parameter so that the app can then in
# turn send the user where they need to be.
get "/u/:id", AppController, :send_home
end
scope "/api/v1", BookmarkerWeb do
pipe_through :api
# CORE API ENDPOINTS
# Create a new bookmark
post "/bookmark", APIController, :create
# Get all your bookmarks
get "/bookmark", APIController, :index
# Get a single bookmark by ID
get "/bookmark/single/:id", APIController, :show
# OTHER USEFUL ENDPOINTS
# Delete a bookmark
delete "/bookmark/:id", APIController, :delete
# Return all posts of a category
get "/bookmark/category/:category", APIController, :index_category
# Return a list of all categories
get "/bookmark/categories", APIController, :index_categories
end
# Enables LiveDashboard only for development
#
# If you want to use the LiveDashboard in production, you should put
# it behind authentication and allow only admins to access it.
# If your application does not have an admins-only section yet,
# you can use Plug.BasicAuth to set up some basic authentication
# as long as you are also using SSL (which you should anyway).
if Mix.env() in [:dev, :test] do
import Phoenix.LiveDashboard.Router
scope "/" do
pipe_through :browser
live_dashboard "/dashboard", metrics: BookmarkerWeb.Telemetry
end
end
# Enables the Swoosh mailbox preview in development.
#
# Note that preview only shows emails that were sent by the same
# node running the Phoenix server.
if Mix.env() == :dev do
scope "/dev" do
pipe_through :browser
forward "/mailbox", Plug.Swoosh.MailboxPreview
end
end
end