Sure, but probably not today.
Can you give an example?
Edit: sorry, didnât notice that you replied already.
use Phoenix.Controller, log: false
works right?
Could you explain this more concretely?
@tmbb As in Iâd like to have a way to be able to generate my own match functions while still generating helpers and all that. So instead of just this:
post "/:ah_tag/requirement/:id/student/:pidm/:date/edit", RequirementController, :student_update, as: :ah_requirement
Iâd like to be able to add other things such as a function that is called on the id
or pidm
or date
or so variables that ensure validity, or else the match fails on this one and it goes to another one, along with priority and so forth. Though honestly Iâd like to actually be able to decorate the callbacks in a module instead and then âregisterâ that module with the Router and have it build up the list. Iâd like to be able to do something like:
@route(
priority: 10,
params: %{
is_allowed: can?(&1, %SomePermission{}),
id: &Accounts.get_id/1,
date: &Timex.parse(&1, "{YYYY}-{0M}-{D}")},
can_access_record: can?(&1, %SomePermission{id: &2.id, date: &2.date}), # Referencing past values
)
def list(conn, params) do
...
end
But if those tests fail then this route isnât ever even matched and other can attempt to be matched, etcâŠ
It can still be efficient, phoenix makes a dispatch tree at compile-time of efficient path matcherâs, then it runs down a list with checks (that save values for re-use on later potential matches) until it gets one that matches, then calls it passing in the data. This is the way some native-code web frameworks work and it is so very convenientâŠ
That causes a problem in which you canât predict the order of route matching. Itâs a problem in some python frameworks like flask and pyramid. Registering all your routes in the Router at least makes sure they are matched in a given order
Eh in those perhaps, but in the ones Iâve used itâs entirely predictable. Like the one Iâm enjoying most is Rocket in Rust, you should give it a try.
HmâŠThat rocket thing still requires you to declare the routes in the Router, but it does allow you to decorate the parameters near the handler. I bet you can do something similar with Elixir by having some macros decorate the conroller actions
Yes, exactly what I was proposing!
The router also needs to be enhanced to allow a fallback if the function fails (a special return type perhaps? then the encoding could happen in-action
or so).
Thatâs a major problem with function clauses and pattern matching: theyâre not composable. They are more efficient because the compiler can optimize the checking for patterns, but thereâs no way of matching subsequent clauses if the previous one has matched.
The only way to do that is through a (less efficient) linear check, and use seomthing like {:ok, value}
tuples in the return values (Iâve learn this the hard way when working on Darwin)
They are though I strongly wager. You use pattern matching on the path and type of method and so forth, then further dispatch via functions. You donât need to jump out of the pattern matching side, only the function tests, the pattern matching becomes very âsetâ once you build up the route tree.
Basically this moves the tests that almost every function does already out of their functions while also allowing them to dispatch based on different things and types.
I wish conn
was renamed to req
and a separate âcontextâ was also used for storing values. Like if a Plug decodes a header that sets a deadline for this request, doesnât make sense to put that decoded integer/time in the connection or the request, it goes in the âcontextâ.
Renaming conn
is just because I think it is odd, especially since these days a connection can end up being used for multiple HTTP requests.
I think âcontextâ should actually use the process dictionary, but still good to define a separate interface and standard key names because it shouldnât be tied to Phoenix.
Thanks for the input! Thatâs exactly what I did https://github.com/akoutmos/telemetry_filter :). Iâll go ahead and close the PR now.
That would work for controllers that I ownâŠbut wonât work for something that is in my dependencies like https://github.com/deadtrickster/prometheus-plugs for example.
more jobs and projects.
I am hunting Elixir and Phoenix projects to work on⊠from a long timeâŠ
I have plug for that:
defmodule MyAppWeb.Plugs.Health do
@behaviour Plug
import Plug.Conn
@moduledoc """
Catches requests to `/health` and returns statistics about running applications.
"""
@enforce_keys [:applications]
defstruct [:applications]
@impl true
def init(opts) do
apps = Keyword.fetch!(opts, :applications)
unless is_list(apps) and Enum.all?(apps, &is_atom/1) do
raise ArgumentError,
":applications is required to be list of atoms, got #{inspect(apps)}"
end
%__MODULE__{applications: apps}
end
@impl true
def call(%Plug.Conn{path_info: ["health"]} = conn, opts) do
versions = for app <- opts.applications, into: %{}, do: {app, version(app)}
conn
|> put_resp_header("content-type", "application/json")
|> send_resp(200, Jason.encode_to_iodata!(%{applications: versions}))
|> halt()
end
def call(conn, _opts), do: conn
defp version(app) when is_atom(app) do
case Application.spec(app, :vsn) do
nil -> nil
vsn -> List.to_string(vsn)
end
end
end
That is simply put before Plug.Telemetry
entry in Endpoint
and it just never is handled by Phoenix.Logger
nor any other handler.
Thank you for such an amazing framework!
This is the single wish my team has after our first Phoenix project in the last 5 months:
I wish for a faster time between I save a file and I see the changes in the browser. This would result in a better developer experience.
Some considerations:
- Weâve learned to analyse the compilation tree using
mix xref graph
and used Module.concat to avoid a lot of dependencies. - It happens that we have some pretty big LiveView templates that take 10 seconds to recompile. We donât know how to work around other than putting them in separate views. Weâre still waiting for a hint here.
- There are a few low level files (contexts and schemas) which very many views depend upon. Changing such file results in a slow recompilation time.
Edeliver and distillery were driving me bonkers. I switched to a dokku deployment and havenât looked back.
Fantastic walkthrough here: