Crowdhailer

Crowdhailer

Creator of Raxx

Raxx - Interface for HTTP webservers, frameworks and clients (1.0 now released!)

Raxx is an alternative to Plug and is inspired by projects such as Rack(Ruby) and Ring(Clojure).

1.0-rc.1 is now available. To use it requires a server, the examples here can be experimented with by adding {:ace, "~> 0.15.2"} to a projects dependencies, NOTE 1.0-rc.0 is equivalent to 0.14.0

Raxx models HTTP as message passing between client and server. There are two flavours to this model.

First is the simple case where a complete request is a single message from client to server and a complete response as a single message from server to client. This is the model successfully exploited by Rack.

The second cases is for streaming where a series of messages are sent in either/both directions. For HTTP this series of messages begins with a head, consisting of all header information plus a few extra details (path for request, status for response). There is then the body broken into 1 or more parts and finally a tail which may contain no further information or may include some trailers.

Simple

           request -->
Client ============================================ Server
                                   <-- response

A server can implement the handle_request/2 callback to use this model in the simplest cases.
For example:

defmodule HomePage do
  use Raxx.Server

  @impl Raxx.Server
  def handle_request(%{method: :GET, path: []}, _state) do
    response(:ok)
    |> set_header("content-type", "text/plain")
    |> set_body("Hello, World!")
  end
end

Streaming

           tail | data(1+) | head(request) -->
Client ============================================ Server
           <-- head(response) | data(1+) | tail

A server can implement the handle_head/2, handle_data/2 & handle_tail/2 callbacks to react to parts of the request as they become available

defmodule Upload do
  use Raxx.Server

  @impl Raxx.Server
  def handle_head(%{method: :PUT, path: ["upload"] body: true}, _state) do
    {:ok, io_device} = File.open("my/path")
    {[], {:file, device}}
  end

  @impl Raxx.Server
  def handle_data(data, state = {:file, device}) do
    IO.write(device, data)
    {[], state}
  end

  @impl Raxx.Server
  def handle_tail(_trailers, state) do
    response(:see_other)
    |> set_header("location", "/")
  end
end

Raxx.Server has one final callback handle_info/2 for dealing with updates from other processes within the application. Several more examples are available in the README.

Goals

Raxx is designed as an alternative to Plug but not a replacement. This thread is meant to be just about Raxx developments, see this previous topic for why I started developing an alternative to plug.

  • model the communication between Client and Server as messaging to be consistent with the erlang/Elixir world view.
    This is the main difference to plug which uses a connection model.
  • support all HTTP patterns including streaming of requests and/or responses.
    In this way it is an evolution of Rack.
  • Require only pure functions, even when implementing a stateful server.
    Familiar anyone who has implemented a GenServer.

Most Liked

Crowdhailer

Crowdhailer

Creator of Raxx

This release ships with no new exciting features, hooray!
All deprecation warnings from 0.x versions have been removed.

For conversations pre 1.0 see this thread.

Simple web tookit

Raxx is a toolkit to make web application with Elixir simple.
It is designed to get out of the way and let you develop any kind of application.

https://github.com/crowdhailer/raxx

Thanks

To everyone who is using Raxx and taken the time to give feedback, thanks.
If you want to join in, check the slack channel.

Extra special thanks to all contributors.

Next

With the core stabilised priorities can now shift.

Ecosystem

The Raxx ecosystem already has support for logging, static files, cors, sessions and more.
Each of these extensions to the core library can now drive towards their own 1.0 release.

Documentation

This is something that can always be improved,
however now the core API is stable efforts documentation and guides will be accurate for much longer.

Getting started

Raxx.Kit is the quickest way to get started with raxx projects.
I want to work on this to increase it’s utility and get newcomers moving even faster.

Further integrations

Finally I hope to spend some time on some more ambitious experiments;

An integration with Absinthe would be interesting as Raxx is great when just building an API service.
Drab and Texas are also libraries that I would like to try out.

Perhaps the most ambitious, because I don’t know what the endpoint looks like, is to try and do more with GenBrowser. The idea of actors on the client and server is a very appealing prospect.

Help wanted

I won’t be able to do all of the next steps on my own.
Contributions are always welcome and now is a great time to get involved.

Documentation is always a good place to start or maybe you have a particular integration that you need.

I am very happy to help you if you want to get started contributing.

Updating

To use 1.0 update any dependent libraries that you need, to the following versions.
These are all non-breaking changes with respect to their previous versions.

# mix.exs

defp deps do
  [
    {:ace, "~> 0.18.6"}
    {:raxx_logger, "~> 0.2.2"}
    {:raxx_view, "~> 0.1.4"}
    {:raxx_static, "~> 0.8.3"}
    {:raxx_method_override, "~> 0.4.1"}
  ]
end

Otherwise you can use {:raxx, "~> 1.0", override: true}.

Crowdhailer

Crowdhailer

Creator of Raxx

Raxx now has a simple client for HTTP/1.1

Examples

synchronous

request = Raxx.request(:GET, "http://example.com")
|> Raxx.set_header("accept", "text/html")

{:ok, response} = Raxx.SimpleClient.send_sync(request, 2000)

asynchronous

request = Raxx.request(:GET, "http://example.com")
|> Raxx.set_header("accept", "text/html")

channel = Raxx.SimpleClient.send_async(request)
{:ok, response} = Raxx.SimpleClient.yield(channel, 2000)

Simple Client

Client is simple because it makes very few assumptions about how to deal with requests and responses.

For example.

  • Cookies are not managed, each request is handled in isolation
  • Connections are not limited or reused, each request gets a new connection

These omissions of functionality make the client much simpler to work with and reason about.
They are also not limitations in many cases. An API client probably doesn’t use cookies.

Composable requests

Because a Raxx.Request is just a data structure,
using this client separates the logic of building the request from the side effect of sending it.

This makes it very easy add custom functionality for your own clients.

 import Raxx

def set_request_id(request, request_id) do
  request
  |> set_header("x-request-id", request_id)
end

def set_json_payload(request, json) do
  request
  |> set_header("content-type", "application/json")
  |> set_body(Poison.encode!(json))
end

# later
request = Raxx.request(:POST, "http://api.com/create_user")
|> set_request_id("12345")
|> set_json_payload(%{"username" => "alice"})

The value of this separation for me in my own projects has been with testing.
It’s now very easy to create invalid requests. just forget to set a request_id and then send it to the API.

Raxx 0.15.8 adds Raxx.SimpleClient

Crowdhailer

Crowdhailer

Creator of Raxx

Core library streamlined

From 0.18.0 the core raxx library is focusing on being an interface.
This is in preparation for a stable 1.0 release. This focus allows extensions such as session and cores can continue to be iterated upon.

When upgrading it is advised to upgrade to 0.17.6 and handle warnings before moving to 0.18.0

See CHANGELOG for details

Where Next?

Popular in Announcing Top

tmbb
I’ve published the first version of my Makeup library. It’s a syntax highlighter for Elixir in the spirit of Pygments, Currently it highl...
New
mspanc
I am pleased to announce an initial release of the Membrane Framework - an Elixir-based framework with special focus on processing multim...
New
josevalim
EDIT: since Ecto 3.0 final version is out, this post was amended to use the final versions in the instructions below. Hi everyone, We a...
New
blatyo
The best overview for how things are tied together is this presentation. Modules and functions are pretty well documented at this point, ...
New
mbuhot
Leverage Open Api 3.0 (Swagger) to document, test, validate and explore your Plug and Phoenix APIs. Generate and serve a JSON Open API ...
New
Qqwy
Hello everyone, I wrote a small library today called MapDiff. It returns a map listing the (smallest amount of) changes to get from map...
New
cjen07
parameterized pipe in elixir: |n&gt; edit: negative index in |n&gt; and mixed usage with |&gt; are supported example: use ParamPipe ...
New
hpopp
After just over two years in development, this latest version of Pigeon is what I finally consider done in regards to my original vision ...
New
Qqwy
TypeCheck: Fast and flexible runtime type-checking for your Elixir projects. Core ideas Type- and function specifications are const...
336 14327 100
New
marcuslankenau
I feel kind of stuck with the absence of a proper xml library for Elixir. Currently I use SweetXML which was ok for me more or less to pa...
New

Other popular topics Top

marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a &gt; b) do {:ok, "a"} end if (a &lt; b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36128 110
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement