ruevaughn

ruevaughn

Hi everyone, I am very new to the Erlang / Elixir / Phoenix scene, so sorry if i’m posting this in the wrong spot, or my terminology is off, feel free to correct me on anything since i’d rather learn.

I’m currently reading and following along with the “Programming Phoenix” book and have a few question about module plugs.

So far, what I understand is that for a module plug to be a ‘module plug’, it needs two functions, init/1 and call/2.

In the book, we make a module called Rumbl.Auth. This module uses the expected init/1 and call/2 functions, but also adds others, such as login/2, login_by_username_and_pass/4 and some others.

Are these ‘other’ functions (login, and login_by_username_and_pass) relying on call/2 in order to operate properly? Or are they completely isolated and ran independently?

Here is the Plug i’m working on… auth module plug

My question is due to me trying to understand when ‘call’ is actually being executed by Phoenix.

I understand I add the module to my router like so

defmodule Rumbl.Router do
use Rumbl.Web, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
    plug Rumbl.Auth, repo: Rumbl.Repo
  end

But i’m not sure when ‘call’ is actually getting called since I never explicitly call it. Is it getting called every time I run another function within that module? Or does it get called once? I understand init gets called during compile time to set things up for call, and call/2 gets executed at runtime.

I guess i’m confused why ‘call’ is even needed in this case, and why I can’t just treat the module (other than the fact that it needs call/2 to be considered a plug) as a module. Is call there just for the sake of being called a ‘plug’?

I hope my question makes sense. Sorry if it’s something blatant i’m missing. Excited to read any replies. Been really enjoying Functional / Erlang / Elixir / Phoenix so far… I haven’t been this excited to learn something in a long time.

Showing Posts 1 to 8

hubertlepicki

hubertlepicki

Phoenix actually never performs the “call” itself as far as I can tell. Phoenix is nothing more than a set of plugs and supporting libraries.

You are right about the init function, it gets called only when app stars. The call function, on the other hand, will be called on each request.

When a HTTP request comes in, Cowboy server is the first that starts handling such request. plug library adds hooks, builds up the chain of plug middlewares, and calls it, I believe here: plug/lib/plug/adapters/cowboy/handler.ex at 2df667389dbaebb0e2102343c8d7a6ed4de6e280 · elixir-plug/plug · GitHub

So, calling “call” happens on each and every request. Moreover, those calls get nested so a pipeline of plugs get processed by some macro (plug/lib/plug/builder.ex at main · elixir-plug/plug · GitHub) and when one call finishes, another call is executed, until some plug returns a valid response, in such case it is halted, response returned to the browser by cowboy. You don’t have to manually call upstream plugs because of smart macros that do it for us.

Basically, a request comes in → cowboy handler executed → plug1.call() → plug2.call() → plug3.call() etc.

bobbypriambodo

bobbypriambodo

You can think of this:

pipeline :browser do
  plug :accepts, ["html"]
  plug :fetch_session
  plug :fetch_flash
  plug :protect_from_forgery
  plug :put_secure_browser_headers
  plug Rumbl.Auth, repo: Rumbl.Repo
end

will generate this:

conn # the initial conn handled by cowboy, passed on to Phoenix
|> accepts(["html"])
|> fetch_session
|> fetch_flash
|> protect_from_forgery
|> put_secure_browser_headers
|> Rumbl.Auth.call(repo: Rumbl.Repo)

Any request that goes to your app will be run through that pipeline first. You don’t have to explicitly call call/2.

Edit: actually my explanation is missing some details. Before going through the pipeline, the connection from first arrives at the Endpoint and went through a series of Plugs before going to the Router and, subsequently, the pipeline.

Does that make sense?

OvermindDL1

OvermindDL1

Actually closer to this (still not perfectly accurate, but keeps the init in this idea):

conn # the initial conn handled by cowboy, passed on to Phoenix
|> accepts(["html"]))
|> fetch_session()
|> fetch_flash()
|> protect_from_forgery()
|> put_secure_browser_headers()
|> Rumbl.Auth.call(Rumbl.Auth.init(repo: Rumbl.Repo))

But yeah, it is the ‘pipeline’ call that does the plugs there. In something like Endpoint the plugs are run via the plug builder that builds the ‘state’. :slight_smile:

bobbypriambodo

bobbypriambodo

And to answer this:

Those other functions are pure functions. They don’t depend on call/2 whatsoever and, as you said, are isolated from one another.

It might be nice to remember that even though Rumbl.Auth is a module plug, it is also a module. In Elixir (and many other FP languages), a module is usually just a collection of functions.

The login/2, login_by_username_and_pass/4, etc. are plain functions. Although login/2 fulfils the contract of a function plug, it is not used as such. They are called with Rumbl.Auth.login(user), and so on.

The reason that those functions are in the Rumbl.Auth module is most likely because as the name implies, they deal with user authentication, therefore it makes sense to group them under an Auth module.

ruevaughn

ruevaughn OP

Lots of great info guys - thank you so much. It makes a lot more sense to me - modules plugs are still Elixir modules - so any other functions within them are isolated from init/1 and call/2 (correct?), but they’re still used to contain like functionality, such as authentication.

Along with that, the plug will get executed (call/2 init/1 on startup) on each and every request since I plugged it into the Browser Pipeline. That happens when Cowboy handles it as @hubertlepicki pointed out.

It’s all becoming a little clearer. Thanks guys, still learning as I read through your posts.

josevalim

josevalim

Creator of Elixir

A small correction: init is called when the app compiles.

ruevaughn

ruevaughn OP

Thanks Jose! Great book, much appreciated. Where do I go to submit any errors / suggestions I find?

josevalim

josevalim

Creator of Elixir
— All posts loaded —

Where Next? Top

Trending in Discussions Top

budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
axelson
Hi there! :wave: @frigidcode and I (but mostly him) have been running an Elixir Book club, we’re almost done with Designing Elixir Syste...
New
achempion
I’ve been using Emacs as my main code editor for more than a two years. It’s a custom build version although I’ve tried doom emacs and sp...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New
jtormey
Lately I’ve been thinking about how to organize components as a LiveView application grows. One of the pain points I’ve found (for myself...
New
Null-logic-0
What IDE or editor are you using for Elixir development? Personally, I use Zed, and I really like it, but sometimes I wish there were a ...
New

Other Trending Topics Top

KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
OndrejValenta
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly) AI dream has many faces, but general...
New
CodeSync
Code BEAM Europe 2026 – Call for Talks is Open! We’re excited to announce that Code BEAM Europe 2026 is now open for talk submissions :t...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews