Crowdhailer

Crowdhailer

Creator of Raxx

Implementing middleware using `defoverridable` and `super`

EDIT: I have written a blog post on this topic

I have been implementing middleware using the defoverridable and super. For example

# myapp.ex

defmodule MyApp do
  use Tokumei.Routing
  use Tokumei.Exceptions
  use Tokumei.ContentLength
  use Tokumei.CommonLogger
  use Tokumei.MethodOverride

  # define routes
end

The Routing module creates a function handle_request/2 and in each middle ware this function is defined as overridable and a new definition created that calls into super as needed. For example the implementation of Tokumei.MethodOverride is as follows, link to code on gihtub.

defmodule Tokumei.MethodOverride do
  def override_method(request = %{method: :POST, query: query}) do
    {method, query} = Map.pop(query, "_method")
    case method && String.upcase(method) do
      nil ->
        request
      method when method in ["PUT", "PATCH", "DELETE"] ->
        method = String.to_existing_atom(method)
        %{request | method: method, query: query}
    end
  end
  def override_method(request) do
    request
  end

  defmacro __using__(_opts) do
    quote do
      defoverridable [handle_request: 2]

      def handle_request(request, config) do
        request = unquote(__MODULE__).override_method(request)
        super(request, config)
      end
    end
  end
end

My questions are:

  • Is there any cost to repeatedly overriding a function?
  • Are there any other libraries doing similar?
  • General comments about the approach

Most Liked

josevalim

josevalim

Creator of Elixir

I will change the private name of the autogenerated function to include a random component just so people don’t do that.

OvermindDL1

OvermindDL1

I hope there is not much cost! I’ve been using a lot of super to override action/2 in controllers to handle exceptions such as redirect’s when a permission exception is thrown. ^.^

But yeah, I’ve not looked at how super is implemented, hmm…

So it seems to be implemented at:

So it looks up the previous function definition and seems to call it, and just above that is where you see it defines in ets the information of what is overridable, with the store function being at the bottom.

So, it looks like the old/parent definitions are defined with a combination of the name and a counter, so always unique, and defp’d, so calls to them are always ‘local’ calls (in erlang parlance), which is fast.

So no issue, it looks like super is fast, I’d not worry about lots of them at all. :slight_smile:

OvermindDL1

OvermindDL1

Also entirely an implementation detail and you should not do this, but you could ‘directly’ call an older version of a function by using its hidden/internal name (for a ‘blah’ function it would be the function name of :"blah (overridable #{count})" for whatever count you want to go ‘up in the stack’). ^.^

Crowdhailer

Crowdhailer

Creator of Raxx

I have publish the following blog post. Describing how to implement middleware with macros. I have been using this method for a while and it has been useful

Crowdhailer

Crowdhailer

Creator of Raxx

Well that is great news. I like the way we can have an essentially native middleware solution. :slight_smile:

Where Next?

Popular in Questions Top

sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
logicmason
Hi there, I'm working through my first release with elixir/phoenix. I've built a release with distillery and found that it crashes when I...
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
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
makeitrein
Hey all, just started picking up Elixir last week and am writing a scraper as a learning project. Baby step #1 is extracting the number ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
gonzofish
I’m currently trying to understand how to join three tables using Ecto. All the examples I’ve seen use 2, so maybe I’m just missing somet...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New
jc00ke
Expanding on this topic: https://forum.elixirforum.net/t/map-typespec-question/19217 Let’s say I have a map with required and optional k...
New

Other popular topics Top

JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1140 51847 244
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
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
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
273 38985 115
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New

We're in Beta

About us Mission Statement