ostap

ostap

Matching all subdomains in Phoenix routing

I love how one can define a host where the last bit would automatically get matched:

scope "/", host: "about.mysite." do`

But it’s impossible to do the opposite end:

scope "/", host: ".mysite.com" do

(for matching all remaining subdomains)

What are the the implications that prevent this from being possible and what are the alternatives for implementing wildcard subdomain matching in a Phoenix project?


Out of curiosity found that this logic is defined in Plug.Router.Utils.build_host_match:

def build_host_match(host) do
  cond do
    is_nil(host) -> quote do: _
    String.last(host) == "." -> quote do: unquote(host) <> _
    is_binary(host) -> host
  end
end

Therefore I naively tried adding this matching rule :sweat_smile::

      String.first(host) == "." -> quote do: _ <> unquote(host)

But it’s not that easy, since it results in:

Compiling 1 file (.ex)

error: a binary field without size is only allowed at the end of a binary pattern, at the right side of binary concatenation and never allowed in binary generators. The following examples are invalid:

    rest <> "foo"
    <<rest::binary, "foo">>

    "foo" <> rest
    <<"foo", rest::binary>>


  lib/my_app_web/router.ex:1

Marked As Solved

sodapopcan

sodapopcan

In short, the “match any subdomain” clause in the router is to just not specify the :host option. The subdomain itself will be available in conn.host so you could pull it out in a plug and do whatever you need to do with it.

If you want different routes depending on the presence of a subdomain, that’s a little different. There are a few discussions around here about it but I’m having trouble finding the ones I found helpful. I do have the (abandon) project I was using it in, though. In short you want to make a plug, check if there is a subdomain then delegate to another router. Maybe there is an easier way at this point? In any event, here is my code:

# lib/my_app_web/subdomain_router.ex
defmodule MyAppWeb.SubdomainRouter do
  # This is just a regular router but with subdomain specific routes
end
# lib/my_app_web/plugs/subdomain_plug
defmodule MyAppWeb.SubdomainPlug do
  import Plug.Conn

  def init(opts), do: opts

  def call(conn, router) do
    case get_subdomain(conn.host) do
      subdomain when byte_size(subdomain) > 0 ->
        conn
        |> fetch_session()
        |> put_session(:subdomain, subdomain)
        |> router.call(router.init({}))
        |> halt()
      _ -> conn
    end
  end

  defp get_subdomain(host) do
    root_host = MyAppWeb.Endpoint.config(:url)[:host]

    if root_host == "localhost" do
      # This handles tests
      ""
    else
      String.replace(host, ~r/.?#{root_host}/, "")
    end
  end
end
# BOTTOM of lib/my_app_web/endpoint.ex
defmodule MyAppWeb.Endpoint do
  # ...
  plug MyAppWeb.SubdomainPlug, MyAppWeb.SubdomainRouter
  plug MyAppWeb.Router
end

Maybe it’s easier at this point? I did always find this to be a little bit of a pain point in Phoenix. Actually, have you tried simply host: "." at all? I can’t remember if that’s a thing or not and don’t feel like spinning up that app :sweat_smile:

Where Next?

Popular in Questions Top

fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
vac
Hi, I’m quite new in Elixir and I’m trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and I...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: The documentation above suggests that while ...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29603 241
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement