I’ve been working on splitting my routes up into multiple routers like this:
defmodule MainRouter do
...
forward "/api", ApiRouter
end
defmodule ApiRouter do
...
scope "/", Api, as: :api do
scope "/v1", V1, as: :v1 do
resources "/users", UserController
end
end
end
Everything is pretty much working here except for my link helpers. To generate a link for the ApiRouter I can do ApiRouter.api_v1_user_path(conn, index), which will generate a path to /v1/users. The problem is it’s missing the /api portion of the path. I expected it to generate /api/v1/users, but I get why it wouldn’t. I assume the /api portion is being gobbled up by the initial Router and only the remainder of the path is being forwarded to the ApiRouter.
Is there a built in way to get my helpers to output the leading /api or do I need to just roll my own helper method to do this?
Passing Phoenix.Endpoint's config a url option with path set to /api would do what you’re looking for at the whole-application level, but there’s nothing quite as clean for this situation.
You can always use a combo with NGINX as a reverse proxy to send to the correct app / router.
Also I think with you can have your routes in order (top Main, API Bellow), so you can correct the API initial to also “/api” and it will work.
Well mine is structured as a singular web application with libraries for ‘modules’ (different sections of the website), among other libraries. Each module just gives out a router to be forwarded to simply. Using nginx to route differently makes no sense as it is all the same server, and the issue is with *_path results not including the forwarded prefix, so nginx would not help with that either. In my case it’s not an /api route but rather a multitude of things that route around.
That’s very similar to my setup as well. I have several scoped routes that I’d like to split up into individual Routers. Some of those are for various APIs, others are stuff like /admin. I have found several references to using match instead of forward.
I was able to get the Plug.Router method to work and it seems to be the way to go. I created a new plug:
# Web.Plugs.Router
defmodule Web.Plugs.Router do
use Plug.Router
# You must include these two Plugs or you'll receive an error
# that's a little hard to track down. It's documented, but I
# missed it initially
plug :match
plug :dispatch
match "/api/*_", to: Web.ApiRouter
match "/admin/*_", to: Web.AdminRouter
match _, to: Web.Router
end
I then updated my endpoint to use my new router plug.
# Web.Endpoint
defmodule Web.Endpoint do
...
# Replace your original router with your new plug
# Web.Router
plug Web.Plugs.Router
end
Then within each router I added the full path, which allowed me to use router specific helpers without having to do anything extra.
defmodule Web.ApiRouter do
...
scope "/api", Web.Api, as: :api do
pipe_through [:api]
scope "/v1", V1, as: :v1 do
resources "/users", UserController
end
end
end
iex> Web.ApiRouter.Helpers.user_path(conn, :index)
"/api/v1/users"
mix phx.routes now includes the full path per Router as I’d originally wanted.
> mix phx.routes Web.ApiRouter
api_v1_user_path GET /api/v1/user Web.Api.V1.UserController :index
This seems to be the best way to handle this as you can then use your routes and helpers as you normally would without having to jump through hoops to ensure the forward path is being prepended.
proxy_app includes web_app_1 and web_app_2 as dependency. Sometimes I might need to broadcast events from web_app_1 and web_app_2. is there a way I can achieve that?