HTTP is message passing
Or - Why I stopped using Plug
In conclusion, Plug is not idiomatic Elixir (or erlang) because of its impure interface. My solution is a pure interface called Raxx.
HTTP describes communication between clients and servers via the web. Below is a quote from the rfc7230 introduction.
The Hypertext Transfer Protocol (HTTP) is a stateless application- level request/response protocol that uses extensible semantics and self-descriptive message payloads for flexible interaction with network-based hypertext information systems.
This introduction describes both requests and responses as messages. Communication between web endpoints is therefore a system using message passing.
GenServer
Message passing is a completley natural concept to Elixir.
OTP even provides an idiomatic way to build servers, using the GenServer
module.
Below is a simple GenServer
implementation that will send a response to a client request message.
In this example the client is just another beam process.
defmodule MyServer do
use GenServer
def handle_call(:request, _from, state) do
{:reply, :response, state}
end
end
Raxx.Server
Raxx.Server
is designed for idiomatic handling of request and response messages.
The only difference is the messages are from a web client instead of beam process.
Below is a simple Raxx.Server
implementation.
You can see the similarities to the GenServer
example.
defmodule MyApp do
use Raxx.Server
def handle_request(_request, _state) do
response(:ok)
end
end
There are a few differences between the implementations that reflect the differences between sending messages over the web and within the beam vm.
-
A
Raxx.Server
is started for each request; thereforehandle_request
is the first function called and aninit
callback is not required. -
Each HTTP message exchange is isolated to its own process;
there is no need for a
from
argument to be passed tohandle_request
. -
There is no need to return a new state in
Raxx.Server
implementation, the process is terminated as soon as the reponse is sent.
What about streaming
One of the design goals for Plug was to accomodate streaming. This was an argument against interfaces like Rack, where a complete request or response would need to be loaded into memory.
Raxx is loosely based on Rack but does not have these drawbacks.
Streaming can be managed in an efficient manner using other callbacks available on Raxx.Server
, see the docs for details.
The Raxx toolkit
Raxx is a toolkit for refined web development. It is currently used in production by several companies.
At the core of the project are data structures for Raxx.Request
and Raxx.Response
.
Both are pure data structures which means that they contain no references to processes.
This is different to Plug.Conn
which does contain a process.
This process is the source of odd behaviour such as only being able to read the body once.
A server is needed to run any web application.
Ace
is the first server to run raxx applications and has support for HTTP/1.x and HTTP/2.
Several common components are part of the core libray such as Raxx.Router
and Raxx.Logger
.
More are available in other projects such as Raxx.APIBlueprint
for a documented router
Finally there is Raxx.Kit
.
It is the quickest way to get started with Raxx. This project consists of generators to set up a project with sensible defaults,
as well as the Ace server for your application.
Questions?
If you want to find out more the best thing is to ask on the Elixir Forum or chat to us in the #raxx slack channel.