Cannoli Web Framework
Build web applications with Strada's built-in web framework.
📦 Download Cannoli on GitHub
Overview
Cannoli is Strada's built-in web framework for building HTTP servers. It provides:
Routing
URL path matching and HTTP method handling
Request Parsing
Query params, form data, JSON bodies, headers, cookies
Response Building
JSON, HTML, redirects, custom headers, cookies
File Uploads
Multipart form-data parsing for file uploads
SSL/TLS
HTTPS support with certificate configuration
Static Files
Built-in static file serving with directory listing
Quick Start
func main() int {
my scalar $app = Cannoli::App::new();
# Each route registers a handler: func (hash %req) hash
Cannoli::App::get($app, "/", func (hash %req) hash {
return Cannoli::Response::json(200, "{\"message\":\"Hello, Cannoli!\"}");
});
Cannoli::App::get($app, "/greet", func (hash %req) hash {
my str $name = Cannoli::Request::get_param(%req, "name");
if ($name eq "") { $name = "World"; }
return Cannoli::Response::text(200, "Hello, " . $name . "!");
});
return Cannoli::App::run($app);
}
Cannoli registers a handler per route with
Cannoli::App::get / post / put /
delete_route (paths may be regexes with capture groups).
Each handler takes the request hash %req and returns a
response built with Cannoli::Response::html / text / json(code, body).
See the examples/ directory in the
Cannoli repository
for request parsing, sessions, file uploads, and WebSockets.
Run with:
./strada -r myapp.strada
Visit http://localhost:8080/ to see your app.
Handlers, Request & Response
A route handler has the signature func (hash %req) hash: it
receives the request hash %req and returns a response hash built
with the Cannoli::Response helpers.
Routing
| Function | Description |
|---|---|
Cannoli::App::new() | Create an application |
Cannoli::App::get($app, $path, $handler) | Register a GET route |
Cannoli::App::post($app, $path, $handler) | Register a POST route |
Cannoli::App::put($app, $path, $handler) | Register a PUT route |
Cannoli::App::delete_route($app, $path, $handler) | Register a DELETE route |
Cannoli::App::run($app) | Start the server |
Paths may be regexes with capture groups, e.g. "/users/([0-9]+)".
Reading the Request
| Function | Description |
|---|---|
Cannoli::Request::get_param(%req, $name) | Query/form parameter |
Cannoli::Request::get_header(%req, $name) | Request header value |
Cannoli::Request::header_names(%req) | All request header names |
Building the Response
| Function | Description |
|---|---|
Cannoli::Response::html($code, $body) | HTML response |
Cannoli::Response::text($code, $body) | Plain-text response |
Cannoli::Response::json($code, $json_string) | JSON response (body is a JSON string) |
Cannoli::Response::header(%res, $name, $value) | Add a header to a response |
Example: a small JSON API
func main() int {
my scalar $app = Cannoli::App::new();
Cannoli::App::get($app, "/health", func (hash %req) hash {
return Cannoli::Response::json(200, "{\"status\":\"ok\"}");
});
# Path capture group -> available as a parameter
Cannoli::App::get($app, "/hello/(\\w+)", func (hash %req) hash {
my str $who = Cannoli::Request::get_param(%req, "name");
if ($who eq "") { $who = "World"; }
return Cannoli::Response::text(200, "Hello, " . $who . "!");
});
Cannoli::App::post($app, "/echo", func (hash %req) hash {
my str $msg = Cannoli::Request::get_param(%req, "msg");
my hash %res = Cannoli::Response::text(200, $msg);
Cannoli::Response::header(%res, "X-Echo", "1");
return %res;
});
return Cannoli::App::run($app);
}
More Features
Cannoli also includes form/JSON body parsing, file uploads, cookies and
sessions, static-file serving, chunked/streaming responses, HTTPS/SSL, and
WebSockets. These are demonstrated in the examples/ directory of
the Cannoli repository
(hello_app, api_app, upload_demo,
headers_demo, static_server,
template_demo).