How Routex and Phoenix Router Work Together: A Blueprint for Understanding
View SourceHow Routex, its extensions, and the Phoenix Router work together can be better understood through an analogy. As the saying goes, "a picture is worth a thousand words," this document also includes an illustrative blueprint.
Analogy: the housing project
Imagine you're a real estate developer planning to build several houses. You
have a general vision for the houses (your route definitions in route.ex
) and
some specific ideas about their style and features (your Routex configuration).
# routes
/products
/products/:id
# config
alternatives: %{
"/fr" => %{name: "French"},
"/es" => %{name: "Spanish"}
}
Routex is the architect. It takes your vision (route definitions) and preferences (Routex config) and creates detailed blueprints.
Routex extensions are the architect's specialized tools. These tools allow the architect to refine and customize the blueprints. Without them, the architect could only create basic, unmodified plans.
# input
[
%Route{path: "/products"}
%Route{path: "/products/:id"}
]
# output after transformation by Alternatives extension
[
%Route{path: "/fr/products", metadata: %{name: "French"}},
%Route{path: "/fr/products/:id", metadata: %{name: "French"}},
%Route{path: "/es/products", metadata: %{name: "Spanish"}},
%Route{path: "/es/products/:id", metadata: %{name: "Spanish"}}
]
Once the blueprints are finalized, they're handed off to the construction company: Phoenix Router. Phoenix Router builds the actual houses (your routes) according to the architect's precise specifications. The blueprints are perfectly formatted for Phoenix Router, ensuring a smooth construction process.
# note: incorrect pseudo code
if match?("/fr/products" ), do: ProductLive, :index, metadata: ["French"]
if match?("/fr/products/" <> id), do: ProductLive, :show, metadata: ["French"]
if match?("/es/products" ), do: ProductLive, :index, metadata: ["Spanish"]
if match?("/es/products/" <> id), do: ProductLive, :show, metadata: ["Spanish"]
This explains the first key concept:
Routex generates blueprints from your route definitions and configuration, ready for Phoenix Router to build the actual routes.
Because Routex is the architect, it has intimate knowledge of the house designs. This allows it to create perfectly matching accessories, like custom-designed sunshades or smart garage doors. These are additional features that enhance the houses built by Phoenix Router, adding convenience and functionality.
# generated convenient functions
defmodule Helpers do
def alternatives("/products") do
[
%Route{path: "/fr/products", name: "French"},
%Route{path: "/es/products", name: "Spanish"}
]
end
end
# your usage
This page is available in:
for alt <- Helpers.alternatives("/products") do
<.link navigate={alt.path}>{alt.name}<./link>
end
# output
This page is available in:
<a href="/fr/products">French</a>
<a href="/es/products">Spanish</a>
This leads to the second key concept:
Routex also creates helpful accessory functions that you can use with the houses (routes) built by Phoenix Router. These functions streamline common tasks and improve the overall experience.
Example blueprint
A picture paints a thousand words, or so they say. The blueprint clearly shows how Routex is middleware, plugged between two stages of Phoenix route generation.
Also shown is the use two co-operating extensions: Translations
uses the
:language
attribute set by Alternatives
.
flowchart TD subgraph subGraph1["Routex"] F["ExampleWeb.RoutexBackend.ex"] G["configure/2 callbacks"] H["Alternatives.transform/3 callback"] I["Translations.transform/3 callback"] J["create_helpers/3 callbacks"] K["ExampleWeb.Router.RoutexHelpers"] end subgraph subGraph0["Phoenix"] A["ExampleWeb.Router.ex"] B["Convert to Phoenix.Routes.Route structs"] C["Generate route functions"] D["ExampleWeb.Router"] end A -- "/products/:id" --> B B -- "%{path: /products/:id}" --> H F -- "extensions: [Alternatives, Translations]" --> G G --> H H -- "%{path: ..., attrs: %{lang: fr}} %{path: ..., attrs: %{lang: es}}" --> I I -- "%{path: /produit/:id, attrs: ...} %{path: /producto/:id, attrs: ...}" --> C & J C -- "def match?(/produit/:id), do: ProductController def match?(/producto/:id), do: ProductController" --> D J -- "def alternatives(/products/:id) do %{path: /produit/:id, attrs: %{lang: fr}} %{path: /producto/:id, attrs: %{lang: es}} end" --> K F:::routex G:::routex H:::routex I:::routex J:::routex K:::routex A:::phoenix B:::phoenix C:::phoenix D:::phoenix classDef routex fill:#4d4d4d, stroke:#888, stroke-width:2px, color:#ffffff classDef phoenix stroke-width:1px, stroke-dasharray: 0, stroke:#616161, fill:#FF6D00, color:#424242 style subGraph0 fill:#FFFFFF, stroke:#757575 style subGraph1 fill:#FFFFFF, stroke:#757575
Conclusion
Phoenix Router and Routex, along with its extensions, form a powerful partnership that empowers you to build any route in your web application. Routex expertly designs the intricate pathways of your application's URLs, while Phoenix Router flawlessly constructs them, ensuring a smooth and efficient user experience.