5 releases
0.1.4 | Jul 7, 2024 |
---|---|
0.1.3 | Jul 3, 2024 |
0.1.2 | Jul 3, 2024 |
0.1.1 | Jul 3, 2024 |
0.1.0 | Jul 3, 2024 |
#1167 in HTTP server
45KB
857 lines
orangutan
orangutan is a lightweight and SUPER simple rust web server library inspired by Python's Flask.
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:
[dependencies]
orangutan = "0.1.0"
lib_shared = "0.1.0"
ctor = "0.2.8"
Usage
This is what a minimal orangutan application looks like:
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:
* orangutan being served!
* orangutan running on http://127.0.0.1:8080/hello (Press CTRL+C to quit)
I recommend using software like ngrok 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
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
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.
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:
The order: "Computer"
What if the request does not contain any JSON Values?
Lets use this command:
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:
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:
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.
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
Dependencies
~7–9.5MB
~178K SLoC