+ - 0:00:00
Notes for current slide
Notes for next slide

Raxx.Kit

Lean mean web development

crowdhailer.me

1 / 46

Hi

name - Peter Saxton

@internets - CrowdHailer

@works - nil

2 / 46

Raxx? ✋

Raxx.Kit? ✋

3 / 46

4 / 46

From the beginning

5 / 46
mix archive.install hex raxx_kit
mix raxx.new my_app
6 / 46
defp deps do
[
{:ace, "~> 0.18.6"},
{:raxx_logger, "~> 0.2.2"},
{:raxx_view, "~> 0.1.7"},
{:raxx_static, "~> 0.8.3"},
{:raxx_session, "~> 0.2.0"},
{:jason, "~> 1.0"},
{:exsync, "~> 0.2.3", only: :dev},
# ...
]
end

mix.exs

7 / 46

What is Raxx?

8 / 46

Raxx is stable

{:raxx, "~> 1.0"}

In production since 2017

Next door right now.

9 / 46

Raxx is an Interface

Raxx

defmodule MyApp.WWW do
use Raxx.SimpleServer
def handle_request(_request, _state) do
%Raxx.Response{status: 200, headers: [], body: "Hello, World!"}
end
end

erlang/OTP

defmodule MyServer do
use GenServer
def handle_call(:request, _from, state) do
{:reply, :response, state}
end
end
10 / 46

Raxx is an Interface

defmodule MyApp.WWW.Upload do
use Raxx.Server # ! Raxx.SimpleServer
def handle_head(%{path: ["upload"] body: true}, _) do
{:ok, io_device} = File.open("my/path")
{[], {:file, device}}
end
def handle_data(data, state = {:file, device}) do
IO.write(device, data)
{[], state}
end
def handle_tail(_trailers, state) do
response(:see_other)
|> set_header("location", "/")
end
end
11 / 46

Raxx is a Toolkit

defmodule MyApp.WWW.Greetings do
use Raxx.SimpleServer
def handle_request(request, _state) do
query = Raxx.get_query(request)
Raxx.response(:ok)
|> Raxx.set_header("content-type", "text/plain")
|> Raxx.set_body("Hello, World!")
end
end

Raxx is imported by default.

12 / 46

Raxx is an Ecosystem

defmodule MyApp.WWW.Greetings do
use Raxx.SimpleServer
alias Raxx.Session
use Raxx.View,
arguments: [:user],
template: "path/to/greetings_template.html.eex"
def handle_request(request, %{session_config: conf}) do
{:ok, session} = Session.extract(request, conf)
response(:ok)
|> render(session.user)
end
end
13 / 46

Raxx is an Ecosystem

Ace.HTTP.Service.start_link(
{MyApp.WWW, config},
port: 8080,
# ...
)

Ace - HTTP/(1 & 2) server to run Raxx applications.

14 / 46

What is Raxx.Kit?

15 / 46

Cowboy -> Ace

Plug -> Raxx

Phoenix -> ???

16 / 46
mix raxx.new my_app
--node-assets
--ecto
--docker
--api
17 / 46
  • project structure
  • live reloading
  • templates
  • static assets
  • testing
  • docker integration (--docker)
  • compiled assets (--node-assets)
  • database setup (--ecto)
18 / 46

19 / 46

Capability
Convenience
Convention

20 / 46

Capability

the power or ability to do something

  • Ace
  • EExHTML
21 / 46

Convenience

the state of being able to proceed with something without difficulty

  • Raxx
  • Raxx.Session
  • Raxx.View (works with Plug)
22 / 46

Convention

behaviour that is considered acceptable or polite to most members of a society

  • Raxx.Kit
23 / 46

Principles

24 / 46

Less is More

The cheapest, fastest, and most reliable components are those that aren’t there.

Gordon Bell

25 / 46

Remove unnecessary features

Old

@route_name :users
route ["users"], request do
:GET ->
# ...
:POST ->
# ...
end

New

def handle_request(%{path: ["users"], method: :GET}, _) do
# ...
end
def handle_request(%{path: ["users"], method: :POST}, _) do
# ...
end
26 / 46

Delegate

27 / 46

Delegate

Supervisor.child_spec({Task, fn() ->
System.cmd("npm", ["run", "watch:js"], cd: "lib/my_app/www")
end}, id: :watch_js),
Supervisor.child_spec({Task, fn() ->
System.cmd("npm", ["run", "watch:css"], cd: "lib/my_app/www")
end}, id: :watch_css),

--node-assets

28 / 46

Opt in

Without a database

mix raxx.new my_app
mix phx.new my_app --no-ecto

With a database

mix raxx.new my_app --ecto
mix phx.new my_app
29 / 46

Mind your own business
View
Controller

30 / 46

31 / 46
  • SQL
  • NoSQL
  • EventSourcing/CQRS
  • Memory Image
  • Hexagonal Architecture
  • Onion Architecture
  • Bring your own

Raxx supports all of these architectures...

32 / 46
  • SQL
  • NoSQL
  • EventSourcing/CQRS
  • Memory Image
  • Hexagonal Architecture
  • Onion Architecture
  • Bring your own

Raxx supports all of these architectures...

because it assumes none of them

33 / 46

Libraries > Frameworks

children = [
{MyApp.WWW, [[port: 4000]]}
{MyApp.API, [[port: 4001]]}
{MyApp.Admin, [[port: 4002]]}
]

lib/my_app/application.ex

setup do
{:ok, service} = MyApp.WWW.start_link(%{}, port: 0)
# etc
end

test/my_app/www_test.ex

34 / 46

Functional cohesion

Functional cohesion (best)

Functional cohesion is when parts of a module are grouped because they all contribute to a single well-defined task of the module.

https://en.wikipedia.org/wiki/Cohesion_(computer_science)

35 / 46

Functional cohesion

my_app/
├── www/
├── actions/
├── login.ex
├── login.html.eex
36 / 46

Functional cohesion

defmodule MyApp.WWW.Login do
use Raxx.SimpleServer
use Raxx.View, arguments: []
def handle_request(%{method: :GET}, _state) do
response(:ok)
|> render()
end
def handle_request(request = %{method: :POST}, _state) do
# ...
end
end
37 / 46

Future plans

38 / 46

Stability

39 / 46

Better erlang support

handle_request(_Request, _State) ->
Response = raxx:response(ok),
raxx:set_body(Response, <<"Hello, World">>).
40 / 46

New conventions - Forms

defmodule MyApp.API.CreatePost.Form do
use Ecto.Schema
@primary_key false
embedded_schema do
field(:pass_token, :binary_id)
field(:idempotency_key, :string)
end
defp cast(raw) do
keys = Map.keys(Map.from_struct(struct(__MODULE__)))
Ecto.Changeset.cast(__MODULE__, raw, keys)
|> Ecto.Changeset.apply_action(:insert)
end
end
41 / 46

New conventions - Forms

defmodule MyApp.API.CreatePost do
use Raxx.SimpleServer
alias MyApp.API.CreatePost.Form
def handle_request(request, _state) do
{:ok, payload} = Jason.decode(request.body)
{:ok, data} = Form.cast(payload)
end
end
42 / 46

New conventions - Error Handling

defmodule MyApp.API.CreatePost do
use Raxx.SimpleServer
require OK
def handle_request(request, _state) do
OK.try do
payload <- Jason.decode(request.body)
data <- Form.cast(payload)
after
response(:created)
rescue
error ->
MyApp.API.format_error(error)
end
end
end
43 / 46

44 / 46

More Buzzwords

mix raxx.new my_app
--graphql
--event_sourcing
--kubernetes
45 / 46

Questions?

@CrowdHailer

46 / 46

Hi

name - Peter Saxton

@internets - CrowdHailer

@works - nil

2 / 46
Paused

Help

Keyboard shortcuts

, , Pg Up, k Go to previous slide
, , Pg Dn, Space, j Go to next slide
Home Go to first slide
End Go to last slide
Number + Return Go to specific slide
b / m / f Toggle blackout / mirrored / fullscreen mode
c Clone slideshow
p Toggle presenter mode
t Restart the presentation timer
?, h Toggle this help
Esc Back to slideshow