Учитывая, что у вас есть список пользовательских маршрутов, хранящихся в базе данных, вы можете вручную проверить, совпадает ли путь входящего запроса с одним из них. Regex может помочь вам решить эту проблему изящно (хотя это не так эффективно, как скомпилированные маршруты):
defmodule RouteMatcher do
def find(routes, path) do
Enum.find_value(routes, nil, &match(&1, path))
end
defp match(route, path) do
pattern = String.replace(route, ~r/:(\w+)/, ~S"(?<\g{1}>[\w-]+)")
regex = ~r/^#{pattern}$/
case Regex.named_captures(regex, path) do
nil -> nil
map -> {route, map}
end
end
end
Теперь предположим, что это список всех определенных маршрутов вбаза данных:
routes = [
"/v1/users",
"/v1/users/:user_id",
"/v1/users/:user_id/posts",
"/v1/users/:user_id/posts/:post_id",
"/v1/users/:user_id/posts/:post_id/:comment_id",
]
Затем функция RouteMatcher.find/2
вернет первый маршрут, который соответствует заданному пути, вместе с соответствующими параметрами (если не найдено ни одного маршрута, он просто вернет nil
):
RouteMatcher.find(routes, "/v1/users")
#=> {"/v1/users", %{}}
RouteMatcher.find(routes, "/v1/users/psy")
#=> {"/v1/users/:user_id", %{"user_id" => "psy"}}
RouteMatcher.find(routes, "/v1/users/psy/posts")
#=> {"/v1/users/:user_id/posts", %{"user_id" => "psy"}}
RouteMatcher.find(routes, "/v1/users/psy/posts/hello-world")
#=> {"/v1/users/:user_id/posts/:post_id", %{"post_id" => "hello-world", "user_id" => "psy"}}
RouteMatcher.find(routes, "/v1/users/psy/posts/hello-world/45")
#=> {"/v1/users/:user_id/posts/:post_id/:comment_id", %{"comment_id" => "45", "post_id" => "hello-world", "user_id" => "psy"}}
RouteMatcher.find(routes, "/unknown/route")
#=> nil