# 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;
}
}
```