The Cayla Web Framework

Cayla makes easy creating web application with Ceylon.

Creating a simple application in seconds

Import the Cayla module

module my.module "1.0.0" {
  import cayla "0.2.0";
}

Write the controller

import cayla { ... }

object controllers {
  route("/")
  shared class Index() extends Controller() {
    shared actual default Response handle() => ok().body("Hello World");
  }
}

shared void run() {
  value application = Application(controllers);
  application.start().always((Runtime|Exception arg) => print(arg is Runtime then "started" else "failed: ``arg.string``"));
  process.readLine();
}

Build and run!

> ceylon compile my.module
...
> ceylon run my.module/1.0
started
Packages
cayla
cayla.descriptor
cayla.pattern
cayla.router
Dependencies
ceylon.net1.0.0
java.base7
vietj.vertx0.3.0
Annotations
route
shared Route route(String path)

Annotate a controller to define its route

Route
shared Route

A route configuration

Functions
error
shared Status error()

Create an 500 status response

notFound
shared Status notFound()

Create an 404 status response

ok
shared Status ok()

Create an 200 status response

run
shared void run()

Run a basic application example.

Classes
Application

A Cayla application.

Creating a Cayla application

An application is created by provided a container in which controllers are discoved.

Object container

Creates an application with a top level container object, the object is scanned for the nested controllers.

object controllers {
  route("/")
  shared class Index() {
    shared actual default Response handle() => Response.ok().body("Hello World");
  }
}
void run() {
  value application = Application(controllers);
  application.start();
  process.readLine();
}

Package container

Creates an application with a package container object, the package is scanned for the nested controllers.

void run() {
  value application = Application(`package my.application`);
  application.start();
  process.readLine();
}

Application life cycle

The start method starts the application and returns a Runtime Promise which:

  • is resolved with the Runtime object when the application is fully started
  • is failed with the reason of the failure when the application cannot be started

This Promise can be used to be aware of the application life cycle:

Promise<Runtime> runtime = application.start(); 
runtime.always((Runtime|Exception arg) => print(arg is Runtime then "started" else "failed: ``arg.string``"));
Body
shared Body

The body response extends the Status with a body

Controller
shared abstract Controller

The base class for web controllers. A controller must extend this class, its attributes are mapped to the request parameters.

Attributes of this class should:

  • declares the String type (later Boolean, Integer, etc…)
  • be shared
  • be immutable

A controller serves two purposes: . to serve a request . to produce an URL that will provide an address for this controller

route("/")
shared class Index() extends Controller() {
  shared actual default Response handle() => Response.ok().body("Hello World");
}

Our Index controller:

  • extends the Controller interface
  • is mapped to the server root via the [route] annotation
  • overrides the handle method for serving the default page

Mapping a request parameter to the controller can be achieved by declaring a corresponding attribute:

route("/greeter")
shared class Greeter(String name) {
  shared actual default Response handle() => Response.ok().body("Hello ``name``");
}

The Greeter controller is mapped to the /greeter path and can be invoked with an URL like /greeter?name=Cayla.

The controller string produces an URL for invoking this controller, the URL is generated using:

  • the path declared by the route annotation
  • the controller attributes

Let's redefine our Index controller:

route("/")
shared class Index() extends Controller() {
  shared actual default Response handle() => Response.ok().body("Say hello to <a href="``Greeter("Cayla")``">Cayla</a>");
}

The response body will contain an URL that will look like http://localhost:8080/greeter?name=Cayla. The string method redefined by the base Controller class:

  • takes care of generating the correct URL, including the parameter encoding
  • provides a safe way for generating URL that is enforced by the Ceylon compiler and is refactorable in the Ceylon IDE

When more context is required during the request, the invoke method can be overriden instead of the handle method. The RequestContext class provides access to the full content of the request.

RequestContext

The request context provides the information available during a request such as:

  • the Vert.x request
  • generating an URL for a controller
Response
shared abstract Response

The response to a request.

Runtime
shared Runtime

The application runtime.

The runtime is obtained from the Application.start method.

Status
shared Status

A status response provides a simple http response with a status code and headers.