orangutan 0.1.4

Flask-like super simple and lightweight web server framework for rust
Documentation
# orangutan

orangutan is a lightweight and SUPER simple rust web server library inspired by Python's [Flask](https://flask.palletsprojects.com/en/3.0.x/).

## Installation (cargo)

Unfortunately, you must add more than one crate to use orangutan because of the macro. This will be fixed in the future but for now I am sorry for the inconvenience.

In the Cargo.toml add:

```toml
[dependencies]
orangutan = "0.1.0"
lib_shared = "0.1.0"
ctor = "0.2.8"
```

## Usage

This is what a minimal orangutan application looks like:

```rust
use orangutan::*;

// Use the 'route'-macro to define the path, method(s) and a handler
#[route(path="/hello", method="[POST, GET]")] 
fn hello_handler(request: &Request) -> Response {

    // Handler has to return a Response           
    let mut res = Response::new();

    // Use the 'insert'-method to insert text/json into the Response     
    res.insert("Hello!"); 

    res 

}

fn main() {    
    // Create an new Orangutan
    let mut app = Orangutan::new("127.0.0.1:8080"); 

    // This automatically makes the Orangutan run with the handler and routes assigned to it.      
    app.run();

    // Now you have a web server listening on http://127.0.0.1:8080/hello 
    // Simple, right
} 
```

Output of the program:

```bash
* orangutan being served!
    *  orangutan running on http://127.0.0.1:8080/hello (Press CTRL+C to quit)
```

I recommend using software like [ngrok](https://ngrok.com/) to make the web server public, as there is no way of doing it with orangutan.

# Examples

orangutan is quite a powerful and useful tool. Here are some of the things that orangutan can do!

## Variables in path

```rust
use orangutan::*;

// Same as defining a normal route but with the path containing the type and variable name.
#[route(path="/<str:username>", method="[GET, POST]")]
fn username_handler(request: &Request) -> Response {
    // This handler is responsible for every request in the path: "/something"
    // The name of the variable (username) is defined after the variables type 

    let mut res = Response::new();          

    // We use the get_var() method to get the value of the variable in the request
    let username: String = request.get_var("username");

    // We can do whatever we want with the username
    res.insert(format!("Hello, {}", username));    

    res

}

// Same thing with the username path but now the value of the variable is i32
#[route(path="/<int:number>", method="[POST, GET]")]
fn number_handler(request: &Request) -> Response {
    // This handler is responsible for every request in the path: "/something"
    // Same as username handler except the value of the variable is i32.  

    let mut res = Response::new();          

    let number: i32 = request.get_var("number");

    res.insert(format!("{} * 2 = {}", number, number*2));    

    res

}

fn main() {    
    let mut app = Orangutan::new("127.0.0.1:8080");   

    app.run();     
}
```
## JSON Requests

In this example I will show you how to handle Requests that contain JSON data

```rust
use orangutan::*;

#[route(path="/order", method="[GET, POST]")]
fn order_handler(request: &Request) -> Response {

    let mut res = Response::new();          

    // .json() returns an Option<Value>, where Some represents the JSON Value and None means that there is no JSON Value in the request
    let order_data = request.json();

    // Let us use match to see if the request contains JSON Value or not
    match order_data {
        // Great. The reqeust contains JSON Value
        Some(data) => { 
            let order: Option<&Value> = data.get("order");

            println!("The order: {}", order.unwrap());
        }
        None => { println!("This means that the request does not contain any JSON data");}
    }    

    res
}

fn main() {    
    let mut a = Orangutan::new("127.0.0.1:8080");   

    a.run();     
}
```

A great way to test how this works is by utilizing tools like curl on Linux. Lets see how our program behaves.

```bash
curl -i -H "Content-Type: application/json" -X POST -d '{"order":"Computer", "OS": "Linux"}' http://127.0.0.1:8080/order
```

Lets see how out program responses to this:

The output of the program:

```bash
The order: "Computer"
```

What if the request does not contain any JSON Values?

Lets use this command:

```bash
curl -X GET -H "Content-Type: text/plain" -d "This is not Json Value" http://127.0.0.1:8080/order
```

And again the output is this:

```bash
This means that the request does not contain any JSON data
```

If the request does contain JSON Value but the Value does not contain the "order" field then our program will 'panic' BUT that does not crash the server thankfully.

## Aborting requests

Sometimes you need to simply return an error. This is how:

```rust
use orangutan::*;

#[route(path="/only_vip", method="[GET, POST]")]
fn user_satus_handler(request: &Request) -> Response {

    let mut res = Response::new();          

    let user_data = request.json();
    
    match user_data {        
        Some(data) => { 
            let user_status: Option<&Value> = data.get("user_status");

            if user_status.unwrap() != "VIP" {
                // Use the abort method to create an error for Response. Only 403, 404 and 500 are valid errors for now.
                res.abort(request, 403);
            } else {
                res.insert("Welcome to the club!");
            }            
        }

        None => { res.abort(request, 404) }
    }    

    res
}
```

## Writing Responses

There are many ways of making Responses. Here are some different ways of doing the same thing.

```rust
use orangutan::*;

#[route(path="/", method="[GET, POST]")]
fn handler(request: &Request) -> Response {

    let mut res = Response::new();          

    // Here are 3 methods for doing the same thing
    res.set_content_type(ContentType::TextHtml);
    res.set_status(200);
    res.append("Hello!");

    res.insert("<p>Hello!</p>");

    res.insert("Hello!");
    res.set_content_type(ContentType::TextHtml);

    res
}
```

## Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

## License

[MIT](https://choosealicense.com/licenses/mit/)