How to structure a Phoenix project with frontend and api?

Hi everybody,

I need some advice on structuring a Phoenix project. My app consists of a LiveView based web app and now I plan to provide an API too. For the API I want to use GitHub - xerions/phoenix_swagger: Swagger integration to Phoenix framework to create the OpenAPI frontend and API definition.

I see two options: I restructure my project into an umbrella project - ecto backend + web frontend + API. Or I just create a second router for the API and just add it two my endpoint.

Is there a best practice for that?

Best regards
Oliver

In a stock Phoenix app you get the following router:

> mix phx.new stock
> cat stock/lib/stock_web/router.ex

defmodule StockWeb.Router do
  use StockWeb, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", StockWeb do
    pipe_through :browser

    get "/", PageController, :index
  end

  # Other scopes may use custom stacks.
  # scope "/api", StockWeb do
  #   pipe_through :api
  # end
  
  if Mix.env() in [:dev, :test] do
    import Phoenix.LiveDashboard.Router

    scope "/" do
      pipe_through :browser
      live_dashboard "/dashboard", metrics: StockWeb.Telemetry
    end
  end
end

Note the part commented out. Simple solution is to use that and create new folder in lib/ called stock_api/ (or wtv) that holds all your API logic, and just route API calls (that hit /api scope) to modules in stock_api/. Your “ecto backend” naively maps to contexts and as such should already be separate (at least in terms of file structure, in lib/stock/). As for extracting that into an app separate from your phoenix app, that is a matter of high debate; same for splitting into Umbrella.

Personally I’d start off with a reasonably decoupled monolith and abstract pieces out as I go. As with all technical opinions YMMV

3 Likes