Skip to content

Repository files navigation

Weber

Weber - is a MVC Web framework for Elixir.

weber-256

Join the Community

#WeberMVC on freenode IRC

Mail listing

Build Status

Features

  • MVC web framework;
  • Project generation;
  • Json generation with exjson;
  • Websocket support;
  • HTML helpers;
  • Web controller Helpers.
  • i18n support;
  • Live code/templates update
  • Sessions support;
  • weber-contrib

Quick start

  1. Get and install Elixir from master.
  2. Clone this repository.
  3. Execute make && make test in the weber directory.
  4. Create new project with: mix weber.new /home/user/testWebApp.

Now go to the /home/user/testWebApp and execute there: mix deps.get && mix compile --all --force. Then you can try to run your testWeberApplication with:

./start.sh

or run it in daemon mode:

./start.sh --no-shell

and go to the http://localhost:8080/

For more details see in examples directory and Weber's API.

Directory structure

Dir/FileDescription
./start.shStartup script
./lib/controllersDirectory with web controllers
./lib/helpersHelper functions
./lib/modelsDirectory for models (ecto)
./lib/viewsDirectory with EEx views
./lib/app.exApplication startup settings
./lib/config.exConfiguration file.
./lib/route.exFile with routes declaration
./publicDirectory for static files (css, js ....)

Routing

Routing declaration is in route.ex files:

routeon("GET","/",:Simpletodo.Main,:action)|>on("POST","/add/:note",:Simpletodo.Main,:add)|>redirect("GET","/redirect","/weber")|>on("ANY",%r{/hello/([\w]+)},:Simpletodo.Main,:action)

Also on supports following syntax:

routeon("GET","/","Simpletodo.Main#action")|>on("POST","/add/:note","Simpletodo.Main#add")

It is route macro which value is chain of on functions with 3 parametes:

  • Http method
  • Route path, can be binding (starts with ':' symbol);
  • Module name of controller;
  • Function name from this controller.

Http method can be:

  • "GET"
  • "POST"
  • "PUT"
  • "DELETE"
  • "PATCH"
  • "ANY"

You can set up resource in routing:

routeresources(:Controller.Photos)

It will be the same as

route on("GET", "/controller/photos", :Controller.Photos, :index)
|> on("GET", "/controller/photos/new", :Controller.Photos, :new)
|> on("POST", "/controller/photos", :Controller.Photos, :create)
|> on("GET", "/controller/photos/:id, :Controller.Photos, :show)
|> on("GET", "/controller/photos/:id/edit, :Controller.Photos, :edit)
|> on("PUT", "/controller/photos/:id, :Controller.Photos, :update)
|> on("DELETE", "/controller/photos/:id, :Controller.Photos, :destroy)

Build url from code

You can build url from your elixir code with:

importWeber.Routerouteon("GET","/","Simpletodo.Main#action")|>on("POST","/add/:note","Simpletodo.Main#add")# generates: /add/1link(:Elixir.Simpletodo.Main,:add,[note: 1])

Controllers

Every Weber's controller is just an elixir module, like:

defmoduleSimpletodo.MaindoimportSimplemodeluseWeber.Controllerlayoutfalsedefaction(_,conn)do{:render,[project: "simpleTodo"],[]}enddefadd([body: body],conn)donew(body){:json,[response: "ok"],[{"Content-Type","application/json"}]}endend

Every controller's action passes 2 parameters:

Controller can return:

  • {:render, [project: "simpleTodo"], [{"HttpHeaderName", "HttpHeaderValheaderVal"}]} - Renders views from views/controller/action.html and sends it to response. Or without headers. {:render, [project: "simpleTodo"]}
  • {:render_inline, "foo <%= bar %>", [bar: "baz"]}} - Renders inline template.
  • {:file, path, headers} - Sends file in response. Or without headers {:file, path}
  • {:json, [response: "ok"], [{"HttpHeaderName", "HttpHeaderValheaderVal"}]} - Weber converts keyword to json and sends it to response. Or without headers: {:json, [response: "ok"]}
  • {:redirect, "/main"} - Redirects to other resource.
  • {:text, data, headers} - Sends plain text. Or without headers: {:text, data}
  • {:nothing, ["Cache-Control", "no-cache"]} - Sends empty response with status 200 and headers.

Request params

Sometimes it is necessary for the request parameters in the controller. For this point can be used Weber.Http.ParamsAPI.

defmoduleSimplechat.Main.LogindoimportWeber.Http.ParamsuseWeber.Controllerlayoutfalsedefrender_login([],conn)do# get body requestbody=get_body(conn)## Do something with param#{:render,[project: "SimpleChat"]}endend

If you need to get parameters from query string, it is easy to do with param/1 API. For example you got request for: /user?name=0xAX, you can get name parameter's value with:

defmoduleSimplechat.Main.LogindoimportWeber.Http.ParamsuseWeber.Controllerdefrender_login([],conn)doname=param(:name,conn)## Do something with param#{:render,[project: "SimpleChat",name: name]}endend

You can find the full API at the wiki.

Before/After request hooks

You can define __before__ or after __after__ hooks in your controller. It will pass two parameters:

  • :action - action name
  • conn - connection parameter
defmoduleSimplechat.Main.Logindodefrender_login([],conn)do{:render,[project: "SimpleChat",name: "WeberChat"]}end## Executes before request#def__before__(:render_login,conn)doconnend## Execute after response#def__after__(:render_login,conn)doconnendend

Helper

Html Helper

Html helpers helps to generate html templates from elixir:

defmoduleSimpletodo.Helper.MyHelperimportWeber.Helper.Html# Generates <p>test</p>defdo_somethingdotag(:p,"test")end# Generates <p class="class_test">test</p>defdo_somethingdotag(:p,"test",[class: "class_test"])end# Generates <img src="path/to/file">defdo_somethingdotag(:img,[src: "path/to/file"])endend

Tags with blocks

defmoduleSimpletodo.Helper.MyHelperimportWeber.Helper.Html# Generates <div id="test"><p>test</p></div>defdo_somethingdotag(:div,[id: "test"])dotag(:p,"test")endendend

Include view in your html

Include view helper helps to include other views inside another.

Import in your controller.

importWeber.Helper

Your view.

<p>Test</p><%= include_view "test.html", [value: "value"]%>

Resource Helpers

You can include your static resources like javascript, css, favicon or image files with resource helpers:

## Generates: <script type="text/javascript" src="/static/test.js"></script>script("/static/test.js")# If no value is passed for src it defaults to "/public/js/application.js"script()## Generates: <link href="/static/test.css" rel="stylesheet" media="screen">#style("/static/test.css")# If no value is passed for href it defaults to "/public/css/application.css"style()## Generates: <link href="/public/img/favicon.ico" rel="shortcut icon" type="image/png">favicon("/public/img/favicon.ico")# If no value is passed for href it defaults to "/public/img/favicon.ico"favicon()## Generates: <img src="/public/img/example.jpg" alt="Image" class="some-class" height="100" width="100">"image("/public/img/example.jpg",[alt: "Image",class: "some-class",height: 100,width: 100])## Generates: <audio src="/public/audio/sound">audio("/public/audio/sound")## Generates:# <audio autoplay="autoplay"># <souce src="/public/audio/sound1"></souce># <souce src="/public/audio/sound2"></souce># </audio>#audio(["/public/audio/sound1","/public/audio/sound2"],[autoplay: true])## Generates: <video src="public/videos/trailer">video("public/videos/trailer")## Generates:# <video height="48" width="48"># <souce src="/public/videos/video1"></souce># <souce src="/public/videos/video2"></souce># </video>video(["/public/videos/video1","/public/videos/video2"],[height: 48,width: 48])

Controller Helpers

content_for_layout and layout

NOTE: Now all views and layout files must start with capital letter.

All controllers got main.html by default for views, but you'd might change it.

You can create custom layout for you controller:

Create Layout.html in the lib/views/layouts directory and put there:

<!DOCTYPE html><html><head><title>
My Project
</title><metahttp-equiv="content-type" content="text/html;charset=utf-8" /></head><body><divid="container"><%= @content_for_layout %></div></body></html>

Than declare layout helper in your controller:

defmoduleTestController.MaindouseWeber.Controllerlayout"Layout.html"## Here are some actions#end

And you have lib/views/Main.html with:

Hello World!

Weber puts lib/views/Main.html content inside <%= content_for_layout %> and renders it in the response.

Logging

Weber uses exlager for the logging. For using it just set up:

log: true

in your config and use it:

defmoduleLogTest.MaindorequireLagerdefaction([],_conn)doLager.info"New request"{:render,[]}endend

Internationalization

Important Experemental now

See - Weber Internationalization

{
"HELLO_STR" : "Hello, It is weber framework!",
"FRAMEWORK_DESCRIPTION" : "Weber - is a MVC Web framework for Elixir."
}

and you can use it like:

<span><%= t(@conn, "HELLO_STR") %></span>

in your html template.

Websocket

You can handle websocket connection and incoming/outcoming websocket message in your controllers.

First of all you need to designate websocket controller in your config.ex file in webserver: section, like:

ws:
[ws_mod: :Handler]

After it you must implement 3 callbacks in your controller like this:

defmoduleSimplechat.Main.Chatdodefwebsocket_init(pid,conn)do## new websocket connection init#enddefwebsocket_message(pid,message,conn)do## handle incoming message here#enddefwebsocket_terminate(pid,conn)do## connection terminated#endend

All websocket connections are must start with prefix /_ws/.

Session

Session API

Testing requests

Currently, one way to test requests is using exunit and the hackney http client as we do in [our own tests.] (https://github.com/0xAX/weber/blob/master/templates/default/test/response_test.exs)

This is not as convenient and expressive as more established frameworks like rspec for rails offer but we are planning to improve this in the future.

Dependencies

Contributing

See Contributing.md

Additional info

Author

@0xAX.

About

[WiP] Web framework for Elixir inspired by Rails [#WeberMVC at freenode]

Resources

Contributing

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors