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

mtrudel
Bandit is an HTTP server for Plug and WebSock apps. Bandit is written entirely in Elixir and is built atop Thousand Island. It can serve...
New
bryanjos
Hi, I just published version 0.23.0 of Elixirscript. https://github.com/bryanjos/elixirscript/blob/master/CHANGELOG.md Most of the chan...
New
nikokozak
Hello all, I’ve been working on Svonix - a library for quickly integrating Svelte components into Phoenix views. It’s a much-needed succ...
New
kip
Image is an image processing library for Elixir. It is based upon the fabulous vix library that provides a libvips wrapper for Elixir. I...
622 18934 194
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
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36352 110
New
josevalim
Hello everyone, We have just released NimbleCSV which is a small and fast CSV parsing library for Elixir. It allows developers to define...
New
woylie
I released Doggo, a collection of unstyled Phoenix components. https://github.com/woylie/doggo Features Unstyled Phoenix components....
New
handnot2
Samly can be used to enable SAML 2.0 Single Sign On in a Plug/Phoenix application. This library uses Erlang esaml to provide plug enabl...
New
trisolaran
Hi! :waving_hand: I would like to present LiveSelect, a little library that I wrote to easily add a dynamic selection input to your LV f...
198 10954 107
New

Other popular topics Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29603 241
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement