Cayla makes easy creating web application with Ceylon.
module my.app "1.0.0" { import cayla "0.2.1"; }
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(); }
> ceylon compile my.app ... > ceylon run my.app/1.0 started
Applications are create via the Application objects that takes as argument a Ceylon declaration or an object that is scanned to discover the controllers:
Application(`package my.controllers`)
Application(controllers)
Controllers must extend the Controller interface, they can declare parameters which shall declares the
String
type, be shared and immutable. Such parameters are mapped toquery or path request parameters.
route("/greeter") shared clas Greeter(String name) extends Controller() { shared actual default Response handle() => ok().body("Hello ``name``"); }
route("/greeter/:name") shared clas Greeter(String name) extends Controller() { shared actual default Response handle() => ok().body("Hello ``name``"); }
Controllers can be addressed using the redefined Controller.string method. In a controller the expression
Greeter("Cayla")
will produce the http://localhost:8080/greeter?name=Cayla or the
http://localhost:8080/greeter/Cayla URL.
During an invocation Cayla dispatches the request to the Controller.handle method. This method should implement the controller behavior.
It is also possible to override the Controller.invoke method instead that provides access to the RequestContext class that exposes Cayla objects.
Both methods returns a Response object that is sent to the client via Vert.x
The Response class is the base response, the Status class extends the response class to define the http status and the Body class extends the Status with a response body.
Creating responses is usually done via the fluent API and the top level functions such as ok, notFound or error.
return notFound().body("Not found!!!!");
By default a controller is bound to a route for all Http methods. This can be restricted by using annotations like get, post, head, put, etc…
get route("/greeter") shared clas Greeter(String name) extends Controller() { shared actual default Response handle() => ok().body("Hello ``name``"); }
Packages | |
cayla | |
cayla.descriptor | |
cayla.pattern | |
cayla.router |
Dependencies | ||
ceylon.net | 1.0.0 | |
java.base | 7 | |
vietj.vertx | 0.3.0 |
Annotations | |
connect | shared Connect connect() Declares a binding to the CONNECT http method |
delete | shared Delete delete() Declares a binding to the DELETE http method |
get | shared Get get() Declares a binding to the GET http method |
head | shared Head head() Declares a binding to the HEAD http method |
options | shared Options options() Declares a binding to the OPTIONS http method |
post | shared Post post() Declares a binding to the POST http method |
put | shared Put put() Declares a binding to the PUT http method |
route | Annotate a controller to define its route |
trace | shared Trace trace() Declares a binding to the TRACE http method |
Connect | shared Connect Http CONNECT |
Delete | shared Delete Http DELETE |
Get | shared Get Http GET |
Head | shared Head Http HEAD |
Options | shared Options Http OPTIONS |
Post | shared Post Http POST |
Put | shared Put Http PUT |
Route | shared Route A route configuration |
Trace | shared Trace Http TRACE |
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 | shared Application A Cayla application. Creating a Cayla applicationAn application is created by provided a container in which controllers are discoved. Object containerCreates 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 containerCreates 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 cycleThe start method starts the application and returns a Runtime Promise which:
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:
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:
Mapping a request parameter to the controller can be achieved by declaring a corresponding attribute: route("/greeter") shared class Greeter(String name) extends Controller() { 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 parameter can also be mapped to a path parameter by specifying it in the path: route("/greeter/:name") shared class Greeter(String name) extends Controller() { shared actual default Response handle() => Response.ok().body("Hello ``name``"); } The controller string produces an URL for invoking this controller, the URL is generated using:
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 URL would be http://localhost:8080/greeter/Cayla when using path parameter mapping. The string method redefined by the base Controller class:
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 | shared RequestContext The request context provides the information available during a request such as:
|
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. |