Framework Design

Synchronous

Stateless

Revel provides primitives that keep the web tier stateless for
predictable scaling. For example, session data is stored in the user
cookie, and the cache is backed by a memcached cluster, redis or in-memory.

Modular

Revel is built around composable middleware called filters,
which implement nearly all request-processing
functionality. Developers have the freedom to replace the default
filters with custom implementations (e.g. a custom router).

# get revel framework
go get github.com/revel/revel
# get 'revel' command
go get github.com/revel/cmd/revel
# get samples and run chat app
go get github.com/revel/samples
revel run github.com/revel/samples/chat

Routing

Revel uses a declarative routing syntax. It collects all routes
for an app in a single file, with a simple syntax for matching
requests, extracting arguments from URIs, and specifying
route-specific arguments to the action. Here's a commented
sample.

// Show the hotel information.func(cHotels)Show(idint)revel.Result{hotel:=HotelById(id)returnc.Render(hotel)}// Save the updated hotel information and redirect back to Show.func(cHotels)Save(hotelHotel)revel.Result{// validate and save hotelreturnc.Redirect(routes.Hotels.Show(hotel.Id))}

Controllers

All Actions are methods on a Controller. This teaser shows a couple cool things:

Data binding. Revel binds simple values and structs from
the URL or form and passes them as parameters to your method.
(If you prefer to access them directly from a parameter map, that's ok too!)

Flash. The flash is a cookie that lives for one
request (errors, success messages, etc).

Session. The session is a cryptographically signed
cookie, exposed as a map[string]string.

Results. Redirections take advantage of reverse
routing. Template rendering makes your data available using the
name of the local variable!

Here's an example:

// app/controllers/app.gotypeMyApplicationstruct{*revel.Controller}func(cMyApplication)Register()revel.Result{title:="Register"returnc.Render(title)}func(cMyApplication)SaveUser(usermodels.User,verifyPasswordstring)revel.Result{c.Validation.Required(verifyPassword)c.Validation.Required(verifyPassword==user.Password).Message("Password does not match")user.Validate(c.Validation)ifc.Validation.HasErrors(){c.Validation.Keep()c.FlashParams()returnc.Redirect(routes.Application.Register())}user.HashedPassword,_=bcrypt.GenerateFromPassword([]byte(user.Password),bcrypt.DefaultCost)err:=c.Txn.Insert(&user)iferr!=nil{panic(err)}c.Session["user"]=user.Usernamec.Flash.Success("Welcome, "+user.Name)returnc.Redirect(routes.Hotels.Index())}

Templates

By convention, Revel manages to integrate
Go Templates
easily into the rest of the web app. Here is part of the template
rendered in the Register action shown above.

Note that:

Revel found it automatically using the name of the action.

field is a simple helper function that returns a map
of validation errors and parameter values for the named field.
The app may inject any helper funcs that it wants.

The title variable is available in the template as if
it had been explicitly put in the RenderArgs. (It's used in
header.html in this case)

Interceptors

Interceptors are controller methods that are run before or after
requests, or in response to panics. By embedding a controller
into another, a developer can share interceptors and fields across
many controllers.

As an example, the database module may be used to open a
connection on initialization, made available through a global
handle. Additionally, embedding the db.Transactional type
adds a sql.Txn field plus interceptors that begin and commit
transactions (or rollback on panic).

Filters

Filters are the middleware of the application. They are simple
functions with a specific signature:

typeFilterfunc(c*Controller,filterChain[]Filter)

Even complicated "built-in" functionality like the interceptor
framework is implemented as a filter:

// github.com/revel/revel/intercept.govarInterceptorFilter=func(c*Controller,fc[]Filter){deferinvokeInterceptors(FINALLY,c)deferfunc(){iferr:=recover();err!=nil{invokeInterceptors(PANIC,c)panic(err)}}()// Invoke the BEFORE interceptors and return early, if we get a result.invokeInterceptors(BEFORE,c)ifc.Result!=nil{return}fc[0](c,fc[1:])invokeInterceptors(AFTER,c)}

Revel provides a default stack of Filters which the developer can
override. This makes it easy for the developer to select exactly
the parts of the framework that they want to use.

// Filters is the default set of global filters.// It may be set by the application on initialization.varFilters=[]Filter{PanicFilter,// Recover from panics and display an error page instead.RouterFilter,// Use the routing table to select the right ActionFilterConfiguringFilter,// A hook for adding or removing per-Action filters.ParamsFilter,// Parse parameters into Controller.Params.SessionFilter,// Restore and write the session cookie.FlashFilter,// Restore and write the flash cookie.ValidationFilter,// Restore kept validation errors from cookie.I18nFilter,// Resolve the requested languageInterceptorFilter,// Run interceptors around the action.ActionInvoker,// Invoke the action.}

Nearly all framework functionality is implemented in the filters,
and the filter stack is directly exposed to the developer as part
of the configuration. This makes Revel understandable and modular.

Pluggable template loader -- Presently only Go templates
are supported by Revel (although the developer could use their own
library independently). Providing an interface that makes any
template language pluggable would be ideal.