jeep-train 0.1.0

An experimental high level web framework.
Documentation
# Productive and Efficient Web Framework In Rust Lang

## Introduction

Rust Lang is a programming language that has been a favourite language for stack overflow users for few years. In comparison to a dynamically typed language popular among web developer, rust is very fast, and it could be said that it has more concise syntax.
I made an attempt to explorer the possibility of building productive web framework in rust.

## Features

### Router

Router is implemented in procedural macro. Existing frameworks tends evaluate the user input on runtime, however with procedural macro you can evaluate them on compile-time. This allows you to convert the router definition into simple match statement while giving programmer an opportunity to improve their productivity.

The router syntax is heavily inspired by Elixir/Phoenix (which is a framework heavily influenced by Ruby on Rails)

Macro syntax looks like this:
```rust
router! {
    // ident given after the const keyword becomes the name of the router. 
    const NAME_OF_THE_ROUTER;

    // scope keyword works like the scope keyword in elixir/phoenix
    // proceeding string will be a route
    scope "/api" {
        // you can nest them
        scope "/v1" {
            // syntax for declaring a route is
            // {method} {function_path};

            // so when it receives a get request on "/api/v1" 
            // function named `get` defined in module `api::v1`
            get api::v1::get;
            post api::v1::create;
            delete api::v1::destroy;
        }
    }
    scope "/resource" {
        /// some syntax can be used to declare multiple routes
        resource index::resource;
        // this is an equivalent of 
        
    }
}
```

When expanded, the macro will become.
```rust
const NAME_OF_THE_ROUTER: Router = /* closure */
```


### Middleware

#### Underlying Assumption

Only argument that the middleware takes is Conn, and no values are returned. This allows you to type less, as a static language when you have to type lengthy idents all-over you’re your code, it will quickly become obnoxious and it could lead to error.

I also wanted the macro to act as a 

#### Functions at Glance

Request parameter can be read from methods on this object. 
```rust
fn print_req(conn: Conn) {
    println!();
    println!("Method: {:?}", conn.method());
    println!("Path: {}", conn.path());
    println!("Body: \n    {}", conn.body());
}

```
Response can be set from the method of this object as well.
```rust
fn not_found(conn: Conn) {
    conn
    // obtains a mutex lock on underlying response object
        .mut_resp()
    // set reponse body and status code
        .set_resp(404, "not found");
}
```

#### Plugin

Plugin is a set of reusable set of functions.
Ident given after the const keyword will become the name of the plugin.
```rust
plugin! {
    const DEFAULT_RESPONSE;
    func lucky_seven;
    func default;
}
```
This will expand into 
```rust
const DEFAULT_RESPONSE: Plugin = /* closure for plugin */ 
```

#### Server

Server macro is there to define a function that will invoke a set of logics 
```rust
server! {
    fn resource_server;
    plugin reject_swear_words;
    router RESOURCE_ROUTER;
    plugin DEFAULT_RESPONSE;
}
```
This will expand into
```rust
fn resource_server(conn: Conn) {
    /* closure for plugin */ 
}
```
## Some Other Idea

I initially tried to implement with traits.
The code looked like this:
```rust 
struct MyPlugin;
impl Plugin for MyPlugin {
    fn call(conn: Conn) {
        /* some logic */
    }
}

fn main() {
    let my_server = server::build()
        .plugin(MyPlugin)
        .router(MyRouter)
        .host("localhost:3000")
        .finish();
    my_server.start();
}
```
I eventually dropped this. Since I didn't feel comfortable defining new datatype that doesn't hold any data.

## Potential Improvements

My interest is primary in UX, not performance so I won't even try to discucss about the latter.(maybe in future)

### use of derive macro instead of declarative one

Currently, you need to set the name of server/router/plugin with `fn` or `const` keyword. Which is not very rusty.

I wasn't able to come up with a better plan while I was building it; however, now I think that it could've been a derive macro that applies for functions.
```rust
#[derive(Router)]

fn my_router(conn: Conn) {
    scope "/api" {
        get api::get;
    }
}
```