Phoenix router, no pipelines invoked for 404

Hello,

I have in my router the following generic scope:

  scope "/", MyModule do
    pipe_through(:browser)
    ...

In the pipeline browser, I call a function that sets a locale using put_session :

conn |> put_session(:locale, "fr")

It is working fine.

But, when I try a call a route that doesn’t match anything defined in that scope, for example mywebsite.com/xxxx, it looks like the request does not go through the browser pipeline.

It is coherent with what I read in the doc : “Note that router pipelines are only invoked after a route is found. No plug is invoked in case no matches were found.”

But I would like to have my locale set to render my 404 page, so I need the request to go through the browser pipeline. How can I do that ? I cannot have a more generic scope that “/”.

Thanks :pray:

This is probably not the idiomatic way, but to catch all requests you can put this at the end of of your router

   scope "/" MyModule do
    pipe_through(:browser)
    get "/*path", MyModuelModule, :notfoundrespons   # (Pokemon route, gotta catch em all!)
end

This will take any path including all forward slashes and just put them in an array

Scopes are not matchable by themselves, they’re more like “folders” of matchable routes.

E.g. you can have both of the following routes be matchable even though the scopes point to the same segment.

scope "/" do
    pipe_through(:browser)
    get "/abc", …
end

scope "/" do
    pipe_through([:browser, :auth])
    get "/def", …
end
1 Like

Thanks for your answers. I now understand that “scopes are not matchable by themselves”.

I would like to know if there is an idiomatic way to have any request that is handled as an error (404, 500) go through a specific pipeline.

If you use the generators phoenix will generate a fallbackcontroller that does this. Search for MyFallbackController here :slight_smile: Phoenix.Controller — Phoenix v1.5.13

Thanks for pointing this @askap. But I understand from the doc that the fallback controllers are used as a fallback when the code of a controller crashes. In my case, I would like to have my request go through a pipeline, even if no route matches that request. I don’t have any exception raised by a controller.

Just add a wildcard match in the end of the router and handle the request however you need to.

1 Like

Thank you. Adding a wildcard, I’m able to call a specific controller action. In that action, I can just create the response I need, using put_status, put_view and render functions, as explained in the doc :

def not_found(conn) do
        conn
        |> put_status(:not_found)
        |> put_view(HelloWeb.ErrorView)
        |> render(:"404")
end

https://hexdocs.pm/phoenix/controllers.html#action-fallback