Using Lua

Serving a single page

Start out by creating a Lua file named server.lua, containing these three lines:

server.lua

handle("/", function()
  print("Hello, Lua!")
end)

Make note of the final ).

Now serve the file with the Algernon server, either by using the commandline:

algernon server.lua

Or by selecting the file with the Algernon GUI appliction (on OS X).

When opening the browser at http://localhost:3000 you should see:

Hello, Lua! in the browser.

What's happening here?

  • print is an Algernon function that outputs text to the browser.
  • handle is an Algernon function that takes an URL path (like /or /subpage and handles the connections with the function that is the second argument.
  • function() ... end defines a function in Lua, where ... is the function body.

When Algernon serves pages by using a single Lua script, the script is loaded into memory and not reloaded when the file is saved. When making changes to the script on disk, the server has to be restarted for the browser output to change.

Serving several pages with a single Lua script

Here is another example that serves HTML and CSS:

webpage.lua

handle("/", function()
    content("text/html")
    print[[
    <!doctype html>
    <html>
      <head>
        <title>hi</title>
        <link rel="stylesheet" href="/style.css">
      </head>
      <body>
        Success!
      </body>
    </html>
    ]]
end)

handle("/style.css", function()
    content("text/css")
    print("body { margin: 4em; font-family: sans-serif; }")
end)

Note that Lua is not dependent on using ( and ) for function calls. These are all equivalent:

print("hi")
print "hi"
print[[hi]]

When using the interactive interpreter, the return value of nil is hidden when using print(), but will appear when using the two other variations. When used in Lua scripts, they will behave identically.

What is happening in when webpage.lua is executed?

When a user is visiting (when a HTTP client is requesting) the web page at /, the first function is called. The HTML code between [[ and ]] is served verbatim. The browser will then try to use the CSS file at /style.css and the function for serving CSS will also be called. Once the browser has also received the CSS code, the styled webpage will be displayed, using margins and a sans-serif font.

The content function declares the MIME type of the page that is to be served. Here text/html and text/css is used, but a range of ther MIME types are also available. One could use content("image/png") and then read a .png image from disk and serve that instead. However, serving files by specifying them in code quickly gets old. Serving files from disk is more desirable, especially when Algernon can cache them in memory and serve them quicker than if declared in Lua.

Here is the same HTML and CSS example, using files instead.

Using HTML and CSS

Project directory structure:

webpage/
|-- index.html
|-- style.css

index.html

<!doctype html>
<html>
  <head>
    <title>hi</title>
    <link rel="stylesheet" href="/style.css">
  </head>
  <body>
    Success!
  </body>
</html>

style.css

body {
  margin: 4em;
  font-family: sans-serif;
}

Try serving the webpage directory with Algernon, and you should see a similar result in the browser as when running the webpage.lua script.

If you serve the webpage either with algernon -a webpage or with the Algernon GUI application (OS X with "Development mode" enabled), any changes to the files will immediatly be reflected in the browser upon save.

Now, if only we could do the same thing, but with less verbosity. That's where Amber and GCSS enters the picture.

Using Amber and GCSS

Project directry structure:

webpage2/
|-- index.amber
|-- style.gcss

index.amber

doctype 5
html
  head
    title hi
  body
    Success!

style.gcss

body
  margin: 4em
  font-family: sans-serif

This gives the same result, but with cleaner code. style.gcss is automatically used as the style for index.amber.

But where does Lua enter the picture? If we introduce a file named data.lua, we can use it to provide data to the Amber template.

Using Lua, Amber and GCSS

data.lua

title = "Iteration"
header = "Iterating over a Lua table"
colors = {"red", "orange", "yellow", "green", "blue", "purple"}

index.amber

doctype 5
html
  head
    title #{title}
  body
    h1 #{header}
    div
      each $key, $value in colors
        div[style="color:"+$value] #{$key} #{$value}

style.gcss

body
  margin: 5em
  font-family: sans-serif
  background-color: #202020
  color: #e0e0e0

div
  margin-bottom: 0.25em

Here, the data and functions declared in data.lua can be used in index.amber by using the #{name} for where the values should be inserted. When between brackets ([and ]), the notation looks like just $name. Concatenating strings and looping over tables using each are supported by Amber.

In conclusion

Note that the Lua script could do a lot more than just declare a few variables. Data could be read from or written to a file or database. Values could be calculated, images could be generated and plugins written in other languages than Lua could be called. Algernon comes with a library of Lua functions specifically for creating web applications, but almost anything should be possible to implement.

The Algernon server is even open source, so forking it and extending it for your own purposes is also possible.