https://github.com/ibnz36/snowboard
fast, simple & reliable http rust servers :snowboarder:
https://github.com/ibnz36/snowboard
http rust server
Last synced: 10 months ago
JSON representation
fast, simple & reliable http rust servers :snowboarder:
- Host: GitHub
- URL: https://github.com/ibnz36/snowboard
- Owner: ibnz36
- License: mit
- Created: 2023-10-21T11:29:14.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2024-02-04T13:09:50.000Z (almost 2 years ago)
- Last Synced: 2025-03-22T19:43:27.385Z (10 months ago)
- Topics: http, rust, server
- Language: Rust
- Homepage: https://crates.io/crates/snowboard
- Size: 363 KB
- Stars: 32
- Watchers: 4
- Forks: 3
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.YML
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
- Roadmap: ROADMAP.md
Awesome Lists containing this project
README
# **Snowboard 🏂**


[](https://app.deepsource.com/gh/Brian3647/snowboard/)
[](https://deps.rs/repo/github/Brian3647/snowboard)
An extremely simple (& blazingly fast) library for HTTP & HTTPS servers in Rust
[Request a feature/Report a bug](https://github.com/Brian3647/snowboard/issues)
Table of Contents
- [**Snowboard 🏂**](#snowboard-)
- [**Quick start**](#quick-start)
- [**Async routes**](#async-routes)
- [**TLS**](#tls)
- [**Websockets**](#websockets)
- [**Routing**](#routing)
- [**Integration**](#integration)
- [**JSON**](#json)
- [**ResponseLike**](#responselike)
- [**MSRV (Minimum Supported Rust Version)**](#msrv-minimum-supported-rust-version)
- [**Contributing**](#contributing)
- [**License**](#license)
## **Quick start**
To get started with Snowboard, simply add it to your `Cargo.toml` file:
```toml
[dependencies]
snowboard = "*"
```
Then, create a new Rust file with the following code:
```rust
use snowboard::{headers, response, Method, Result, Server};
fn main() -> Result {
let data = "Hello, world!";
let server = Server::new("localhost:8080")?;
println!("Listening on {}", server.pretty_addr()?);
server.run(move |mut req| {
if req.method == Method::DELETE {
return response!(method_not_allowed, "Caught you trying to delete!");
}
req.set_header("X-Server", "Snowboard");
println!("{req:#?}");
response!(ok, data, headers! { "X-Hello" => "World!" })
})
}
```
And that's it! You got yourself a working server on :8080. Examples can be found in the `examples` folder.
## **Async routes**
You can use the `async` feature and `Server::run_async` to run async routes:
```toml
# Cargo.toml
[dependencies]
snowboard = { version = "*", features = ["async"] }
```
```rust
// src/main.rs
use snowboard::{Request, ResponseLike, Server, Result};
use async_std::task;
use std::duration::Duration;
async fn index(_: Request) -> impl ResponseLike {
task::sleep(Duration::from_secs(1)).await;
"Async works"
}
fn main() -> Result {
Server::new("localhost:8080")?.run_async(index)
}
```
## **TLS**
Use the `tls` feature (which will also install `native-tls`) to use TLS:
```rust
use anyhow::Result;
use snowboard::{
Identity, TlsAcceptor,
response, Server,
};
use std::fs;
fn main() -> Result<()> {
let der = fs::read("identity.pfx")?;
let password = ..;
let tls_acceptor = TlsAcceptor::new(Identity::from_pkcs12(&der, password)?)?;
Server::new_with_tls("localhost:3000", tls_acceptor)?
.run(|request| format!("{request:#?}"))
}
```
You can confirm it works by running `curl -k https://localhost:3000` _(the -k is needed to allow self-signed certificates)_
More info can be found in `examples/tls`.
## **Websockets**
WebSockets are easy to implement with the `websocket` feature. Example (echo server):
```rust
use std::net::TcpStream;
use snowboard::Server;
use snowboard::WebSocket;
fn handle_ws(mut ws: WebSocket) {
while let Ok(msg) = ws.read() {
ws.send(msg).unwrap();
}
}
fn main() -> snowboard::Result {
Server::new("localhost:3000")?
.on_websocket("/ws", handle_ws)
.run(|_| "Try `/ws`!")
}
```
## **Routing**
Routing can be handled easily using the `Url` struct:
```rust
use snowboard::{response, Request, ResponseLike, Result, Server};
fn router(req: Request) -> impl ResponseLike {
// /{x}
match req.parse_url().at(0) {
Some("ping") => response!(ok, "Pong!"),
Some("api") => response!(not_implemented, "👀"),
None => response!(ok, "Hello, world!"),
_ => response!(not_found, "Route not found"),
}
}
fn main() -> Result {
Server::new("localhost:8080")?.run(router);
}
```
## **Integration**
### **JSON**
JSON is supported with the `json` feature (serializing & deserializing):
```rust
use serde_json::Value;
use snowboard::{Response, Server};
#[derive(serde::Deserialize)]
struct Example {
number: isize,
}
fn main() -> snowboard::Result {
Server::new("localhost:8080")?.run(|req| -> Result {
let example: Example = req.force_json()?;
Ok(serde_json::json!({
"number_plus_one": example.number + 1
}))
});
}
```
```rust
use snowboard::Server;
fn main() -> snowboard::Result {
Server::new("localhost:3000")?.run(|r| {
serde_json::json!({
"ip": r.ip(),
"url": r.parse_url(),
"method": r.method,
"body": r.text(),
"headers": r.headers,
})
})
}
```
`force_json` returns a result of either the parsed JSON or a bad request response. If you want to handle the error yourself, use `json` instead.
### **ResponseLike**
Snowboard's `ResponseLike` is designed to work with pretty much anything, but it wont by default with certain cases like `maud`'s `html!` macro. If you happen to use a lot a crate that doesn't work with Snowboard, please open an issue, pr or implement `ResponseLike` for it:
```rust
use snowboard::{Response, ResponseLike, Server};
struct Example {
num: usize,
}
impl ResponseLike for Example {
fn to_response(self) -> Response {
snowboard::response!(ok, self.num.to_string())
}
}
fn main() -> snowboard::Result {
Server::new("localhost:8080")?
.run(|_| Example { num: 5 });
}
```
## **MSRV (Minimum Supported Rust Version)**
The MSRV is 1.60.0, but it might change (lower or higher) depending on which features are enabled.
## **Contributing**
Check [CONTRIBUTING.md](CONTRIBUTING.md) for a simple guide on how to help the project.
## **License**
This code is under the MIT license that can be found at [LICENSE](./LICENSE)