Help language development. Donate to The Perl Foundation

Humming-Bird zef:rawleyfowler last updated on 2023-05-16

3132308c4c9b6cae65c81b9cbce504fbbc19cb7c/

Humming-Bird

![Zef Badge](https://raku.land/zef:rawleyfowler/Humming-Bird/badges/version?) [![SparrowCI](https://ci.sparrowhub.io/project/gh-rawleyfowler-Humming-Bird/badge)](https://ci.sparrowhub.io)

Humming-Bird is a simple, composable, and performant web-framework for Raku on MoarVM. Humming-Bird was inspired mainly by Sinatra, and Express, and tries to keep things minimal, allowing the user to pull in things like templating engines, and ORM's on their own terms.

Features

Humming-Bird has 2 simple layers, at its core we have Humming-Bird::HTTPServer which handles all of the low-level HTTP bits. Then you have the routing stack that handles: routing, middleware, error handling, cookies, etc.

Note: Humming-Bird is not meant to face the internet directly. Please use a reverse proxy such as httpd or NGiNX.

How to install

Make sure you have zef installed.

Install latest

zef -v install https://github.com/rawleyfowler/Humming-Bird.git

Install stable

zef install Humming-Bird

Performance

Around ~20% faster than Ruby's Sinatra, and only improving as time goes on!

See this for a more detailed performance preview.

Examples

Simple example:

use v6.d;

use Humming-Bird::Core;

get('/', -> $request, $response {
    $response.html('<h1>Hello World</h1>');
});

listen(8080);

# Navigate to localhost:8080!

Simple JSON CRUD example:

use v6.d;

use Humming-Bird::Core;
use JSON::Fast; # A dependency of Humming-Bird

my %users = Map.new('bob', %('name', 'bob'), 'joe', %('name', 'joe'));

get('/users/:user', -> $request, $response {
    my $user = $request.param('user');

    if %users{$user}:exists {
        $response.json(to-json: %users{$user});
    } else {
        $response.status(404).html("Sorry, $user does not exist.");
    }
});

post('/users', -> $request, $response {
    my %user = $request.content; # Different from $request.body, $request.content will do its best to decode the data to a Map.
    if my-user-validation-logic(%user) { # Validate somehow, i'll leave that up to you.
        %users{%user<name>} = %user;
        $response.status(201); # 201 created
    } else {
        $response.status(400).html('Bad request');
    }
});

listen(8080);

Routers

use v6.d;

use Humming-Bird::Core;
use Humming-Bird::Middleware;

# NOTE: Declared routes persist through multiple 'use Humming-Bird::Core' statements
# allowing you to declare routing logic in multiple places if you want. This is true
# regardless of whether you're using the sub or Router process for defining routes.
my $router = Router.new(root => '/');

$router.middleware(&middleware-logger); # middleware-logger is provided by the Middleware package

$router.get(-> $request, $response { # Register a GET route on the root of the router
    $response.html('<h1>Hello World</h1>);
});

$router.get('/foo', -> $request, $response { # Register a GET route on /foo
    $response.html('<span style="color: blue;">Bar</span>');
});

my $other-router = Router.new(root => '/bar');

$other-router.get('/baz', -> $request, $response { # Register a GET route on /bar/baz
    $response.file('hello-world.html'); # Will render hello-world.html and infer its content type
});

# No need to register routers, it's underlying routes are registered with Humming-Bird on creation.
listen(8080); 

Middleware

use v6.d;

use Humming-Bird::Core;
use Humming-Bird::Middleware;

get('/logged', -> $request, $response {
    $response.html('This request has been logged!');
}, [ &middleware-logger ]); # &middleware-logger is provided by Humming-Bird::Middleware

# Custom middleware
sub block-firefox($request, $response, &next) {
    return $response.status(400) if $request.header('User-Agent').starts-with('Mozilla');
    $response.status(200);
}

get('/no-firefox', -> $request, $response {
    $response.html('You are not using Firefox!');
}, [ &middleware-logger, &block-firefox ]);

More examples can be found in the examples directory.

Design

Things to keep in mind

Contributing

All contributions are encouraged! I know the Raku community is amazing, so I hope to see some people get involved :D

Please make sure you squash your branch, and name it accordingly before it gets merged!

Testing

Install App::prove6

zef install --force-install App::Prove6

Ensure that the following passes:

cd Humming-Bird
zef install . --force-install --/test
prove6 -v -I. t/ it/

License

Humming-Bird is available under the MIT, you can view the license in the LICENSE file at the root of the project. For more information about the MIT, please click here.