Typed URL parameters in Phoenix

I have a use-case where I need to get integer parameters from a URL (this is best explained by an example):

URL: /messages/34
Matching route: get "/message/:id", MessageController, :show
Parameters passed to controller: %{"id" => "34"}

This works fine when you just pass the parameter straight to a SQL query with Ecto, but in other cases (such as if you were to cache data with an integer key), it is necessary to either convert the string to an integer and handle potential errors in every controller action, or add some sort of logic to the caching layer to handle the conversion.

I was thinking it would be kind of cool to be able to do something like this in your MyApp.Router:

Route: get "/messages/{:id, :integer}", MessageController, :show
Params passed to controller: %{"id" => 34}

Or something similar as an optional way to support automatically handling data conversion. If the parameter passed here failed to parse, a 400 or 404 could be returned by Phoenix.

Anyone have any thoughts?

2 Likes

Have you considered GraphQL? All data going into and out of GraphQL is typed, and you can even build custom types.

2 Likes

I’ve wanted similar things, but it seems difficult to implement as the only things really useful are guards so that you can fall-through failing matches properly, so not really workable from a quick look I had months ago…

My controllers have this stuff:

  def index(conn, %{"id" => id} = _params) do
    happy_path!(else: handle_error(conn)) do
      @perm true = conn |> can?(search(%Perms.Blah{}))
      @arg_test {:ok, {_cnum, uid, obj}} = verify_cnum_uid(id)
      blah = Repo.get(Blah, uid)
      render(conn, :index, obj: obj, blah: blah)
    end
  end

Where something like the verify_cnum_uid above returns a tuple of the result, which if it fails the match will return an appropriate error code over http. It is nicely composable and all.

That’s a really good point actually. We have been looking at GraphQL and it’s definitely something we want to do in the future.

If you want to check it out, http://absinthe-graphql.org/ is the place to start. Feel free to ping me on slack if you run into any issues!

3 Likes

there is also vic/params which is just a wrapper around Ecto and you can then cast params into their ecto type.

2 Likes