• Stars
    star
    401
  • Rank 107,625 (Top 3 %)
  • Language
    Elixir
  • License
    Apache License 2.0
  • Created over 8 years ago
  • Updated about 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Interface for HTTP webservers, frameworks and clients

Raxx

Interface for HTTP webservers, frameworks and clients.

Hex pm Build Status License

See Raxx.Kit for a project generator that helps you set up a web project based on Raxx/Ace.

Simple server

1. Defining a server

defmodule MyServer do
  use Raxx.SimpleServer

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

  def handle_request(%{method: :GET, path: _}, _state) do
    response(:not_found)
    |> set_header("content-type", "text/plain")
    |> set_body("Oops! Nothing here.")
  end
end
  • A request's path is split into segments. A request to GET / has path [].

2. Running a server

To start a Raxx server a compatible HTTP server is needed. This example uses Ace that can serve both HTTP/1 and HTTP/2.

raxx_server = {MyServer, nil}
http_options = [port: 8080, cleartext: true]

{:ok, pid} = Ace.HTTP.Service.start_link(raxx_server, http_options)
  • The second element in the Raxx server tuple is passed as the second argument to the handle_request/2 callback. In this example it is unused and so set to nil.

Start your project and visit http://localhost:8080.

HTTP streaming

An HTTP exchange involves a client sending data to a server receiving a response. A simple view is to model this as a single message sent in each direction. Working with this model corresponds to Raxx.SimpleServer callbacks.

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

When the simple model is insufficient Raxx exposes a lower model. This consists of a series of messages in each direction. Working with this model corresponds to Raxx.Server callbacks.

           tail | data(1+) | head(request) -->
Client ============================================ Server
           <-- head(response) | data(1+) | tail
  • The body of a request or a response, is the combination of all data parts sent.

Stateful server

The LongPoll server is stateful. After receiving a complete request this server has to wait for extra input before sending a response to the client.

defmodule LongPoll do
  use Raxx.Server

  @impl Raxx.Server
  def handle_head(%{method: :GET, path: ["slow"]}, state) do
    Process.send_after(self(), :reply, 30_000)

    {[], state}
  end

  @impl Raxx.Server
  def handle_info(:reply, _state) do
    response(:ok)
    |> set_header("content-type", "text/plain")
    |> set_body("Hello, Thanks for waiting.")
  end
end
  • A long lived server needs to return two things; the message parts to send, in this case nothing []; and the new state of the server, in this case no change state.
  • The initial_state is configured when the server is started.

Server streaming

The SubscribeToMessages server streams its response. The server will send the head of the response upon receiving the request. Data is sent to the client, as part of the body, when it becomes available. The response is completed when the chatroom sends a :closed message.

defmodule SubscribeToMessages do
  use Raxx.Server

  @impl Raxx.Server
  def handle_head(%{method: :GET, path: ["messages"]}, state) do
    {:ok, _} = ChatRoom.join()
    outbound = response(:ok)
    |> set_header("content-type", "text/plain")
    |> set_body(true)

    {[outbound], state}
  end

  @impl Raxx.Server
  def handle_info({ChatRoom, :closed}, state) do
    outbound = tail()

    {[outbound], state}
  end

  def handle_info({ChatRoom, data}, state) do
    outbound = data(data)

    {[outbound], state}
  end
end
  • Using set_body(true) marks that the response has a body that it is not yet known.
  • A stream must have a tail to complete, metadata added here will be sent as trailers.

Client streaming

The Upload server writes data to a file as it is received. Only once the complete request has been received is a response sent.

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
  • A body may arrive split by packets, chunks or frames. handle_data will be invoked as each part arrives. An application should never assume how a body will be broken into data parts.

Request/Response flow

It is worth noting what guarantees are given on the request parts passed to the Server's handle_* functions. It depends on the Server type, Raxx.Server vs Raxx.SimpleServer:

request flow

So, for example, after a %Raxx.Request{body: false} is passed to a Server's c:Raxx.Server.handle_head/2 callback, no further request parts will be passed to to the server (c:Raxx.Server.handle_info/2 messages might be, though).

Similarly, these are the valid sequences of the response parts returned from the Servers:

response flow

Any Raxx.Middlewares should follow the same logic.

Router

The Raxx.Router can be used to match requests to specific server modules.

defmodule MyApp do
  use Raxx.Server

  use Raxx.Router, [
    {%{method: :GET, path: []}, HomePage},
    {%{method: :GET, path: ["slow"]}, LongPoll},
    {%{method: :GET, path: ["messages"]}, SubscribeToMessages},
    {%{method: :PUT, path: ["upload"]}, Upload},
    {_, NotFoundPage}
  ]
end

More Repositories

1

OK

Elegant error/exception handling in Elixir, with result monads.
Elixir
599
star
2

Ace

HTTP web server and client, supports http1 and http2
Elixir
304
star
3

elixir-on-docker

Quickly get started developing clustered Elixir applications for cloud environments.
Elixir
172
star
4

eyg-lang

Experiments in building "better" languages and tools; for some measure of better.
Gleam
151
star
5

raxx_kit

Get started with Raxx + Elixir
HTML
122
star
6

pachyderm

Virtual actors for elixir
Elixir
103
star
7

gen_browser

Transparent bi-directional communication for clients, servers and more
Elixir
68
star
8

plinth

node and browser bindings for gleam
Gleam
56
star
9

watercooler

Building a distributed chatroom with Raxx.Kit
Elixir
25
star
10

server_sent_event.ex

Push updates to Web clients over HTTP or using dedicated server-push protocol
Elixir
20
star
11

awesome-eco

Resources and Prodjects addressing human ecological impact.
12
star
12

vulcanize

Form objects to coerce user input using your value objects
Ruby
10
star
13

AllSystems

Simple Ruby usecases/interactors/service-object to encapsulate business logic
Ruby
10
star
14

typetanic

A few hygenicly namespaced domain objects.
Ruby
6
star
15

rollup-karma-jasmine-example

Calculator project that bundles es6-modules with Rollup. Tests use Jasmine and are run in the browser with Karma
JavaScript
6
star
16

me

All about me
HTML
5
star
17

ace-raxx-clustering-example

An example of how to setup a multi node web service in elixir
Elixir
5
star
18

intention.js

Pure implementation of the JavaScript fetch API exposing an analogue to the promise API.
JavaScript
5
star
19

basic_authentication

Submit and verify client credentials using the 'Basic' HTTP authentication scheme.
Elixir
5
star
20

CORS

Check Cross Origin Request Security headers.
Elixir
4
star
21

comms

Explicit message passing for improved reasoning about actor systems
Elixir
4
star
22

raxx_static

Raxx middleware for serving static content.
Elixir
4
star
23

gleamtours

Tours through various topics in Gleam.
Gleam
4
star
24

greetings-ace-elixir-example

Simple greetings application to showcase developing web services with Ace
Elixir
3
star
25

cookie.ex

Elixir
3
star
26

eex_html

Extension to Embedded Elixir (EEx), that allows content to be safely embedded into HTML.
Elixir
3
star
27

num

Because floats were never really numbers
Elixir
3
star
28

no-code

Notes on no-code programming
3
star
29

raxx_api_blueprint

Route requests based on an API Blueprint
Elixir
3
star
30

carbide.js

Minimal immutable objects in JavaScript
JavaScript
3
star
31

greetings-ace-raxx-erlang-example

Simple greetings application to showcase developing web services with Ace and Raxx in erlang
Erlang
3
star
32

gleamweekly

Gleam is so hot right now. There is so much happening in our wonderful and growing community that you wouldn't want to miss.
HTML
3
star
33

raxx.rs

How to web dev with Rust
Rust
2
star
34

git_status

Compile time status of GIT repository for source code.
Elixir
2
star
35

level

A spirit level for your device. No download required
JavaScript
2
star
36

echo-server.hs

TCP echo server written in Haskell.
Haskell
2
star
37

svg-crop

Output PNG's at a variety of size's and aspect ratios from a single SVG source.
JavaScript
2
star
38

phonegap-vector-assets

Create multiple resolution assets for phonegap applications directly from config.xml
JavaScript
2
star
39

phonegap-icon-set

An example project to generate multiple icons for phonegap
JavaScript
1
star
40

Almighty

Environment recreation and dotfile plus
Shell
1
star
41

IOC-example.js

Inversion of control architecture for JavaScript applications
JavaScript
1
star
42

eyg

Explicit concurrency for intelligible parallel programing.
Rust
1
star
43

cut-the-mustard

Checking your JS environment is up to scratch
JavaScript
1
star
44

svg_agile

SVG manipulation on with touch or mouse
JavaScript
1
star
45

phonegap-screenshot-example

Generating webview screenshots for use in app stores.
JavaScript
1
star
46

lob

Demonstrating realtime connection between web browsers. Powered by ably.io. Created by Workshop14.io
JavaScript
1
star
47

Curriculum-Vitae

Curriculum Vite for Peter Saxton
TeX
1
star
48

HammerHead

A minimal JavaScript utility to help view SVG's on webpages
JavaScript
1
star
49

bbox

Find bounding box dimensions either within or surrounding arbitrary containers
JavaScript
1
star
50

just-job

Just Job is a todo list built from the ground up using the principles of Domain Driven Design(DDD)
Ruby
1
star