Reactive Server Pages

Introduction

Reactive Server Pages (RSP) bring some concepts of reactive languages to the realm of server-side web development.

Traditional server-side web application are implemented as a collection of related pages that access the same shared state (i.e. session variables). Once the web server receives a page request from the client, it executes the dynamic page reading and writing to session variables, and yields a fresh page to the client. The request is handled all at once, and no state (besides the client's session) remains in the server. Hence, there is no notion of sequential execution in a web application, whose life cycle is purely associated with the active client session.

RSP rearrange the way web applications are developed. A web application conceptually becomes a single file that executes from its first to its last line. The programmer can use structured programming with loops and recursive calls. RSP are based on LuaGravity, which extends the Lua language with reactive data and control primitives.

In the following example (which is available online), each time the client accesses the path /next in the application (which triggers the event next), a new page with the counter incremented is generated to the client:

_step = 1
_html = [[I am in step ]].._step

for i=1, 5 do
    _step = i
    await 'next'
end

_html = [[Finished!]]

In LuaGravity, any variable starting with underscores (i.e. _html) is reactive in the sense that it is reevaluated whenever one of its dependencies changes. In the example, whenever _step changes, the _html variable is automatically reevaluated to respect the new value of _step.

In RSP, the current value of the _html variable is the actual page returned to the client whenever the application becomes idle waiting for events.

After iterating from 1 to 5, generating five pages, and also the Goodbye! page, the application terminates. If the client accesses the application again, it restarts, generating the page I am in step 1.

This example illustrates both control and data reactivity in RSP: reactive variables account for data reactivity, while the await call, for control reactivity.

Architecture

An RSP application is accessed from a single URL in the server, as in

http://www.mydomain.com/rsp/myapp/

Accesses to the rsp/ directory are intercepted by the RSP runtime, which executes the file myapp.lua in the configured directory. The application runs to completion or until it waits for events, and returns to the client the current value of the reactive variable _html.

The client interacts with the application in two forms: through events, or by changing reactive variables.

In the following URLs, the first triggers the event next in myapp, while the second changes the value of _var to zero:

http://www.mydomain.com/rsp/myapp/next
http://www.mydomain.com/rsp/myapp/?_var=0

The users do not need to type these URLs themselves, they can be generated by links or forms in the application. In the following example, the link points to the URL http://www.mydomain.com/rsp/myapp/next (which triggers the event next in myapp); while typing rsp in the text box, and pressing the submit button points to the URL http://www.mydomain.com/rsp/myapp/submit?_name=rsp (which sets _name=rsp before triggering the event submit).

<a href="next">Click to go to next step</a>

<form>
    <input type="text"   name="_name"/>
    <input type="submit" name="submit"/>
</form>

In order to support changing variables from the client side, an RSP application must define a table pub with the available variables:

local meta = require 'luagravity.meta'
pub = meta.new {
    _name = ''
}

Trying to set an undefined variable raises an error.

Follows a summary of the architecture of RSP:

  • Application
    • Single file
    • Execution = from first to last line
    • State = globals + locals + PC
  • Client interaction
    • Events
    • Reactive variables
  • Interface
    • The reactive variable _html

An Example: A Shopping Cart

Click here for a more complex example of a simple shopping cart in RSP.

Download & Install

The current version of RSP is 0.1.1 and can be downloaded here.

I also keep a github repository here.

RSP depends on LuaGravity, wsapi, luacrypto, and lfs. To install wsapi-xavante, luacrypto and lfs, you can use luarocks:

# luarocks install lfs
# luarocks install luacrypto
# luarocks install wsapi-xavante

To install RSP, just unpack it to the desired destination:

# tar xvzf luarsp-0.1.1.tgz

Assuming that you will use wsapi-xavante, you can edit the file config.lua to your preferences, and then run the server:

# cd luarsp-0.1.1/
# vi config.lua
# cd examples
# wsapi -c ../config.lua

Then, open your browser and point to one of the applications in the examples/ directory, for example:

http://localhost:8080/rsp/cart/

Acknowledgments

Please contact me if you are using RSP.

Francisco Sant'Anna ()

License

Reactive Server Pages is free software: it can be used for any purpose, including commercial purposes, at absolutely no cost. No paperwork, no royalties, no GNU-like "copyleft" restrictions, either. Reactive Server Pages is certified Open Source software. Its licenses are compatible with GPL.

The MIT License

Copyright (c) 2010 Francisco Sant'Anna

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.