Request and Response cycle in Elixir: Phoenix

Siddhant Singh
Nov 4, 2019 · 5 min read
Image for post
Image for post
Photo by Steve Johnson on Unsplash

When I was studying how controllers work in Ruby, I learned about rails middleware and how Journey is used to routes the incoming request. In Phoenix, we have something called conn.

If you have worked on phoenix before you might have seen this conn required in almost all the places in your application. The “conn” comes into life when you make a request to a phoenix app and dies when the response is sent out. The conn object carries the whole request and response cycle in Phoenix.

Project Setup

Before setup, I assume you’ve already install elixir and phoenix on your machine.

Let’s first create a phoenix app:

mix phx.new <project_name>cd <project_name>mix ecto.createmix phx.server

Now you can go to, http://localhost:4000/, and you will get a phoenix welcome page.

Erlang and Elixir

We all know the elixir is built upon erlang but to understand erlang will give you a better understanding of the elixir. Both use BEAM which compiles Erlang and Elixir source code into Bytecode. BEAM is a part of the Erlang Run-Time System(ERTS). You might want to check out this link if you want to in-depth Elixr and BEAM.

Cowboy

Erlang has Cowboy and Ranch which uses to create a server in Phoenix. It is the same as Nginx but Cowboy has one more advantage over the other server. Cowboy works in combination with Ranch (which is a socket worker pool for TCP protocols) and Cowlib(library for message processing). Since Cowboy is designed to build server. The process starts when you initialize your server.

cowboy:start_http(http, 10, [{port, 80}], [{env, [{dispatch, Dispatch}]}])

After this everything will be handled by Ranch. The cowboy just implements the protocol, for example, HTTP, etc. These protocols are fed into Ranch which will decide how the server will behave.

When the Nginx web server maps a file on the disk to every HTTP request. Cowboy maps every HTTP request to an erlang module. It has no idea about the disk.

dispatch_config = :cowboy_router.compile([
{ :_,
[
{:_, MyApp.Cowboy.Handler, []},
]}
])
{ :ok, _ } = :cowboy.start_http(:http,
100,
[{:port, 8080}],
[{ :env, [{:dispatch, dispatch_config}]}]
)

So MyApp.Cowboy.Handler handles all the incoming HTTP requests.

Phoenix App

Let’s come down to your phoenix app which you’ve just created. When you create a project or type this command:

mix phx.new <project_name>`

It will start the otp_app. So it means when you create your project Elixir is creating an OTP app. I will not get into how OTP works because it’s another big topic in Elixir's world.

To explain this you have to go your mix.exs file and you will see something like this

def application do
[
mod: {Banking.Application, []},
extra_applications: [:logger, :runtime_tools]
]
end

When you run the server using mix phx.server, Elixir starts all the applications listed in the “application” and then it will start your phoenix project. So when I say starting an application, it will call the function name “start” in the module give in ‘mod’.

So when we run the server the start function will get invoked in your application file. So go to your lib/<app-name>/application.ex file you’ll see something like this

def start(_type, _args) do
# List all child processes to be supervised
children = [
# Start the Ecto repository
Banking.Repo,
# Start the endpoint when the application starts
BankingWeb.Endpoint
# Starts a worker by calling: Banking.Worker.start_link(arg)
# {Banking.Worker, arg},
]
opts = [strategy: :one_for_one, name: Banking.Supervisor]
Supervisor.start_link(children, opts)
end

This function creates a supervisor process that monitors two-child supervisor processes for Repo and Endpoint. A supervisor process doesn’t do any actual work, rather, it only checks if the child processes are working or dead. Since our start function started two child processes, both of which are supervisors, it also means that these child supervisors have one or more workers or supervisors.

We don’t need to see the Repo supervisor because it’s for managing database connections. Now let’s explore Endpoint supervisor.

defmodule BankingWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :banking

socket "/socket", BankingWeb.UserSocket,
websocket: true,
longpoll: false
plug Plug.Static,
at: "/",
from: :banking,
gzip: false,
only: ~w(css fonts images js favicon.ico robots.txt)
if code_reloading? do
plug Phoenix.CodeReloader
end
plug Plug.RequestId
plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint]
plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
json_decoder: Phoenix.json_library()
plug Plug.MethodOverride
plug Plug.Head
plug Plug.Session,
store: :cookie,
key: "_banking_key",
signing_salt: "kSKZtoWp"
plug BankingWeb.Router
end

Banking.Endpoint is a child supervisor of the main application in this case Banking is the parent supervisor. You will not see the required start_link function in Endpoint. The line

use Phoenix.Endpoint, otp_app: :banking

is doing a lot of things for you. To get into detail you might have to learn about metaprogramming. Metaprogramming will define the start_link dynamically with all the worker details.

Behind the scene, a lot of things happening which I was not familiar with in starting but when I read about metaprogramming it got me thinking about the functions like ranch. Ranch supervisor is also which is dynamically defined in your phoenix app. This supervisor starts Cowboy process listening at port 4000 on the localhost and is configured to pass all requests to Plug.Cowboy.Handler.

Plug.Adapters.Cowboy.Handler is the module which handles all the request. So what it does is it takes your phoenix application endpoint as an argument and it kind of creates the pipeline between them.

Plug

Before explaining the conn struct it’s important for you to know about the plug.

Plug is a specification for composable modules in between web applications. It is also an abstraction layer for connection adapters of different web servers. The basic idea of Plug is to unify the concept of a “connection” that we operate on. This differs from other HTTP middleware layers such as Rack, where the request and response are separated in the middleware stack. You can think of a plug as a piece of code that receives a data structure, does some sort of transformation, and returns this same data structure, slightly modified. This data structure that a Plug receives and returns is usually called, and represents everything that there is to know about a request.

As plugs always receive and return a connection, they can be easily composable, forming what is called a Plug pipeline. Actually, that is what usually happens. We receive a request, then each plug transforms this request a little bit and pass the result to the next plug, until we get a response.

That’s it for this blog. That was a brief guide on phoenix and how it handles request and response cycle. I will continue this in my next blog where I will explain the conn struct in more detail.

Thankyou

The Startup

Medium's largest active publication, followed by +721K people. Follow to join our community.

Siddhant Singh

Written by

Into Data Science, Machine Learning and Data-Driven Astronomy. If I’m not writing code, I might be reading some random stuff.

The Startup

Medium's largest active publication, followed by +721K people. Follow to join our community.

Siddhant Singh

Written by

Into Data Science, Machine Learning and Data-Driven Astronomy. If I’m not writing code, I might be reading some random stuff.

The Startup

Medium's largest active publication, followed by +721K people. Follow to join our community.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store