1 unstable release

0.1.0 Jul 26, 2020

#893 in HTTP server

Custom license

17KB
331 lines

About

Overview

Jeep train is an experimental high level web framework

The project is purely experimental and it is not meant to be used in a production environment.

The motivation behind the development is to

  • see if procedural macro can help define a runtime efficient router productively
  • explore ways to minimize boilerplate/learning cost

Feature

  • Define your api routes on rails like syntax. API Syntax is straight forward and inputs are converted into match statement
  • Conn object will be passed onto every functions invoked in the process of handling client request and it will act as a primary interface for interacting with request/response data

Routing

It looks like this.

router! {
    const NAME_OF_THE_ROUTER;
    scope "/api" {
        scope "/v1" {
            get api::v1::get;
            post api::v1::create;
            delete api::v1::destroy;
        }
    }
    scope "/resource" {
        resource index::resource;
    }
}

Example

This code can be found on examples/resources.

use jeep_train_prelude::*;
use jeep_train_macro::{ router, server, plugin };
use jeep_train_prelude::server::jeep_train;

fn set_text_header(conn: Conn) {
    conn
        // obtain a mutex on response object for the user
        .mut_resp() 
        // insert a header data 
        .set_headers("content-type".to_owned(), "text".to_owned());
}

fn default(conn: Conn) {
    conn.mut_resp()
        .set_resp(404, "not found");
}

fn lucky_seven(conn: Conn) {
    if conn.path().len() == 7 {
        conn.mut_resp()
            .set_resp(200, "lucky seven!")
    }
}

fn reject_swear_words(conn: Conn) {
    if conn.path().contains("fuck") {
        conn.mut_resp()
            .set_resp(200, "don't swear")
    }
}

plugin! {
    const DEFAULT_RESPONSE;
    func lucky_seven;
    func default;
}

router! {
    const RESOURCE_ROUTER;
    scope "/resource" {
        plugin set_text_header;
        resource resource_module;
    }
}

server! {
    fn resource_server;
    plugin reject_swear_words;
    router RESOURCE_ROUTER;
    plugin DEFAULT_RESPONSE;
}

/// # Routes that it creates
/// 
/// | method | path | function |
/// | --- | --- | --- |
/// | get | /resource/ | resource_module::index |
/// | get | /resource/new | resource_module::new |
/// | post | /resource/ | resource_module::create |
/// | get | /resource/show | resource_module::show |
/// | get | /resource/:id/edit | resource_module::edit |
/// | put | /resource/:id | resource_module::update |
/// | patch | /resource/:id | resource_module::update |
/// | delete | /resource/ | resource_module::destroy |
///
/// Note that `/:id` is a parameterized segment
/// 
fn main() {
    jeep_train("localhost:3000", resource_server);
}

pub mod resource_module {
   /* ...functions  */
}

Benchmark

Jeep train doesn't use regular expression.
However, I think it's uncommon to register a regular expression on router on parameterized path to identify specific format of data.

running 2 tests
test router_actix      ... bench:     836,812 ns/iter (+/- 22,033)
test router_jeep_train ... bench:       1,491 ns/iter (+/- 51)

Detail can be found in benchmark-result

Dependencies

~5–14MB
~173K SLoC