159 lines
5.3 KiB
Elixir
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
|