acb's technical journal

Posts matching tags 'web'

2016/2/25

swiftemplate: Compile-time HTML templates in Swift

Continuing my experiments with the potential of Swift for server-side web applications, I have recently turned my attention to the question of HTML templates. In any HTML-based web app, it is useful to have a way of programmatically generating HTML with data interpolated, which typically is done through templates; HTML documents with special markup. When a page is requested, the template is processed, with the data being inserted into it, generating a HTML document which is sent back to the browser.

There are two ways a templating system may be implemented in a web application framework. On one hand, the framework itself may embed the template engine; the web app in this case would be deployed with a set of templates, which it would parse into an internal representation; then, whenever the app receives a request, the engine uses the template to generate a HTML page. (This is the approach used by many web frameworks written in dynamic languages such as Python and Ruby.) The other alternative is to do the template processing at build time; a tool compiles the template into source code in the language the web application is written in; it is then included in the app, and called as any other piece of code would be. The advantages of this approach are more compact and efficient compiled applications. It is particularly suited to compiled languages like Swift, which already have a build process.

It is with this in mind that, following on from the Malimbe framework, I have developed swiftemplate, a familiar-looking HTML-oriented templating system that generates Swift code.

The swiftemplate syntax

The syntax of swiftemplate will be familiar to people who have used other web application frameworks. A template file consists of content (typically HTML) interspersed with directives, expressions and inline code blocks. Directives begin with %% and occupy their own lines; they include the familiar for and if/else (which are augmented with closing directives), as well as a template directive which defines a template and its arguments. Inline expressions are enclosed in <%= and %>; they must fit on one line, but may contain characters not permissible in Swift's \() interpolation syntax. Code blocks take up multiple lines, and are enclosed in <% and %> brackets (each of which must be on its own line). An example template (for displaying a page about a user of a web application) might look like like:

%% template showUser(user: User)
<%
let posts = user.posts.prefix(5)
%>
<h1>User \(user.name)</h1>
%% if posts.isEmpty
<p>This user has no posts</p>
%% else
<ul>
%% for post in posts
  <li><%= post.title %></li>
%% endfor
</ul>
%% endif
%% endtemplate

The template compilation process

Swiftemplate templates are compiled to Swift code with the swiftemplate command. One or more template files (each potentially containing one or more templates) may be compiled at a time into a Swift source file; one possible invocation could be to compile all the templates into one source filem prior to compilation of the Swift code, like so:

swiftemplate -o Sources/templates.swift Templates/*.swiftemplate

In the emitted source file, each template is converted to a Swift function, having the same name and arguments as in its %% template directive and returning a String; for example, the user page template above would produce Swift code that (if indented) looked something like:

func showUser(user: User) -> String {
  var _ℜ=[String]()
  let posts = user.posts.prefix(5)
  _ℜ.append("<h1>User \(user.name)</h1>")
  if posts.isEmpty {
    _ℜ.append("<p>This user has no posts</p>")
  } else {
    _ℜ.append("<ul>")
    for post in posts {
        _ℜ.append("<li>")
        _ℜ.append(String(post.title))
        _ℜ.append("</li>")
    }
    _ℜ.append("</ul>")
  }
  return _ℜ.joinWithSeparator(" ")
}

(The variable containing the return result is given the name ‘_ℜ’, which stands for “result” and is also unlikely to be used by the template. Needless to say, don't name your templates or template arguments this.)

Composing templates

Given that swiftemplate input files may contain multiple templates, and that templates, in their compiled form, are just Swift functions returning Strings, it is possible to define templates in a modular fashion. Below is an example, also from the user example, which displays a set of contact details using another template as a macro:

%% template contactDetail(name: String, value: String) 
<dt class="detailName">\(name)</dt> 
<dd class="detailValue">\(value)</dd>
%% endtemplate

%% template showUser(user: User)
<h1>User \(user.name)</h1>
<p>\(user.description)</p>
<h2>Contact details</h2<
<dl>
<%= contactDetail("Phone", user.phone) %>
<%= contactDetail("Email", user.email) %>
<%= contactDetail("Twitter", user.twitter) %>
%% // ... and so on
</dl>
%% endtemplate

The state of Swiftemplate

This is the first version of Swiftemplate, and it may well have bugs. Having said that, there are extensive unit tests (though, at the moment, these only work in Xcode; once testing in the Swift build process on Linux matures, they will work there as well).

Swiftemplate is a lightweight template processor; it parses the parts it understand and passes other parts (such as the expressions following an %% if or a %% for) through to Swift without attempting to enforce correct syntax. Which means that if those parts are nonsense, swiftemplate will not warn you, but you will get a Swift compiler error in the machine-generated .swift file containing your processed templates. Be warned!

Swiftemplate runs under OSX (with Xcode) or Linux (with the command-line build tools, and the Foundation module installed), and does not depend on Malimbe or any other code; it is available on GitHub and is distributed under the Apache Licence (i.e., it may be used freely, as long as acknowledgement is provided).

html swift swiftemplate web 0

2016/2/11

Malimbe: an asynchronous server-side web framework in Swift

Recently, I have been experimenting with the open-source beta of Swift for Linux, and in particular looking into its potential as a language for server-side web applications. As such, I present the first draft of my experimental server-side web framework, Malimbe.

Malimbe (named after several species of African weaver bird) is written in Swift and will build on Linux; no attempt has yet been made to make it work on OSX, though it would certainly be possible. The main influences on Malimbe's design have been various Python/WSGI-based frameworks (mainly Pylons/Pyramid) and the Play framework in Scala (though Malimbe is a lot more minimal at this stage). The key design decisions of Malimbe, as it currently stands, are:

  • The use of Futures (as previously described here) for concurrency. HTTP request handlers do not return a HTTPResponse immediately, but return a Future<HTTPResponse>; i.e., an opaque container to a computation, which, once complete, will yield a HTTPResponse. The Future may refer to an ongoing computation, taking place on a background thread, or (for simple responses) may be created pre-completed. Given that Futures are monadic containers (which may be mapped and flatMapped over), a request handler returning a Future<HTTPRequest> could well just call a function returning a Future of, say, a set of database rows or a JSON object fetched from a remote API, and return that mapped into, say, a page of HTML.
  • Malimbe's request-handling mechanism is a chain of objects implementing the HTTPRequestHandler protocol. This protocol defines only one method, which looks like:
    func handleRequest(request: HTTPRequest) -> Future<HTTPResponse>
    
    The request handler objects are typically instantiated with any configuration information they need; for most of them, this will include a next value, containing the next request handler in the chain. If the request handler cannot completely handle the request itself, it will call this and return its value. (Theoretically, it could also modify its return value with map or flatMap, though none of the ones implemented so far do.)

The main source file of a Malimbe web application, as it stands, constructs the chain of request handler, and creates a HTTPServer object (passing the top of this chain to it); requests propagate down the chain until they are handled; at the bottom is typically the Router request handler, which matches methods and paths, extracting arguments from paths, and calling the appropriate handler for each path. This might well look something like:

func itemPageHandler(request: HTTPRequest, args:[String:String]) -> Future<HTTPResponse> {
    let id = args["id"] ?? ""
    // make the item page here...
}

let router = Router(routes:[
	Router.Get("/items/",    handler:itemsListHandler),
	Router.Get("/items/:id", handler:itemPageHandler),
])

let staticFiles = StaticFileRequestHandler(pathPrefix: "/static/", staticDir:appRelativePath("StaticFiles/"), next:router)

let server = HTTPServer(handler: staticFiles)

do {
    try server.start(9999)
    print("started on 9999")

    while(true) {
        NSRunLoop.mainRunLoop().runUntilDate(NSDate.distantFuture())
    }
} catch {
    print("error: \(error)")
}

Malimbe currently has a few request handlers: the path-matching Router shown above; StaticFileRequestHandler, which can conveniently serve static files (such as stylesheets and JavaScript) from a local directory under a certain path, along with a HTTP Basic Authentication middleware; others will be added in future.

HTMLRenderable

Malimbe also has a simple set of objects for generating HTML in Swift code. This, Swiftily enough, has a protocol at its centre, the HTMLRenderable protocol, which allows objects to return HTML representations of them:

public protocol HTMLRenderable {
    /** Return a HTML representation of this object as a String */
    var asHTML: String { get }
}

The Swift String type has been extended to be HTMLRenderable; a string rendered asHTML will be quoted, with angle brackets replaced with &lt; and &gt; so that its contents are displayed as they are. If you wish to pass HTML markup back, there is a HTMLLiteral object you can wrap it in, which renders without any quoting. However, in most cases, you will want to create tags using the HTMLTag type, a HTMLRenderable representing a single tag and its contents (which may include zero or more HTMLRenderables within the tag), like so:

HTMLTag.DIV([
    HTMLTag.SPAN(HTMLTag.B(self.name), "says:", class:"itemtop"),
    HTMLTag.DIV(self.text, class:"itembody")
], class:"guestbookitem")

(The tag's contents are the first rather than last parameters; this is because of quirks in Swift's handling of variadic arguments.)

Of course, since HTMLRenderable is a protocol, there is every reason to extend your data types to implement it, which then allows you to insert them directly in the markup:

extension Item: HTMLRenderable {
    var asHTML: String {
        return HTMLTag.P(
            "Item ", HTMLTag.B(self.id), "(\(self.name))"
        , class: "item").asHTML
    }
}

The state of the framework

Malimbe is an experimental framework, still in an early stage of development. Many pieces that one would expect in a full stack are missing (notably any support for access to databases or web-based APIs). Some of these may be developed separately as other projects and imported as dependencies into Malimbe-based projects, though ideally, Malimbe would integrate them into its design. (For example, once a database framework exists, it would be the intention for it to be wrapped in an asynchronous interface that returns Futures of results.) Other components (such as session middleware, templating libraries, and a configuration system) are also missing at this stage.

Also, because Swift support on Linux is still immature, Malimbe applications will probably not be performant at this stage. For one, at the time of writing, there was no stable Linux port of libdispatch (Apple's concurrency framework, also known as Grand Central Dispatch); Malimbe uses a workaround from a Swift package named NSLinux which fakes this by spawning a thread for each dispatched block; this is obviously not something one would want on a heavily loaded production server. However, once libdispatch is ready, Malimbe will not require significant changes to use it.

Malimbe is available on GitHub, and is distributed under the Apache Licence (i.e., it may be used freely, as long as acknowledgement is provided).

futures linux malimbe swift web 1

2014/4/7

Adventures with Scala, Play, SecureSocial and ReactiveMongo, Part 1

Recently I have been playing with Scala, and particularly with the Play web framework. For what it's worth, Scala is a functional object-oriented language, somewhere between Python and Haskell with the odd Erlangism, bits of Java sticking out in places and an infamously Turing-complete type system, and Play is a Ruby-style web framework implemented in it. The main selling point of Scala, other than the functional niftiness of it, is that it's, as the name suggests, highly scalable; in fact, when Twitter had scaling problems, they rewrote their systems from Ruby on Rails to Scala.)

In the course of my experiments, I have been looking at SecureSocial, a reasonably flexible web identity/authentication framework which allows one to allow users to log in using either local accounts or remote OAuth/OpenID-based services. Also, for the sake of being modern (not to mention scalability), I decided to eschew the traditional SQL databases and go with MongoDB, using the highly asynchronous ReactiveMongo library. Finally, I decided to extend SecureSocial's standard user model, adding extra fields to the user object (among them, capabilities for access control). Unfortunately, there has not until now been much solid documentation on how to bring these elements together, hence this article.

 [...]

mongodb playframework scala securesocial web 3

This will be the comment popup.
Post a reply
Display name:

Your comment:


Please enter the text in the image above here: