Initial commit
Implemented user/users/favicon routes Implemented catchers 404/403 Implemented Responder traits
This commit is contained in:
commit
9da559ff4f
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
Cargo.lock
|
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "routes_rocket"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
rocket = "0.5.0"
|
2
Rocket.toml
Normal file
2
Rocket.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[default]
|
||||||
|
port = 3000
|
233
src/main.rs
Normal file
233
src/main.rs
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
#[macro_use] extern crate rocket;
|
||||||
|
|
||||||
|
use rocket::Request;
|
||||||
|
use rocket::fs::{NamedFile, relative};
|
||||||
|
use rocket::http::{ContentType, Status};
|
||||||
|
use rocket::{response::{self, Responder, Response}, Build, Rocket, request::FromParam};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::io::Cursor;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
fn default_response<'r>() -> response::Response<'r> {
|
||||||
|
Response::build()
|
||||||
|
.header(ContentType::Plain)
|
||||||
|
.raw_header("X-CUSTOM-ID", "CUSTOM")
|
||||||
|
.finalize()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromForm)]
|
||||||
|
struct Filters {
|
||||||
|
age: u8,
|
||||||
|
active: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct User {
|
||||||
|
uuid: String,
|
||||||
|
name: String,
|
||||||
|
age: u8,
|
||||||
|
grade: u8,
|
||||||
|
active: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> Responder<'r, 'r> for &'r User {
|
||||||
|
fn respond_to(self, _: &'r rocket::Request<'_>) -> response::Result<'r> {
|
||||||
|
let base_response = default_response();
|
||||||
|
let user = format!("Found user: {:?}", self);
|
||||||
|
Response::build()
|
||||||
|
.sized_body(user.len(), Cursor::new(user))
|
||||||
|
.raw_header("X-USER-ID", self.uuid.to_string())
|
||||||
|
.merge(base_response)
|
||||||
|
// .header(ContentType::Plain)
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Defining a new type where neither the type nor impl are in our app or crate.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct NewUser<'a>(Vec<&'a User>);
|
||||||
|
|
||||||
|
impl<'r> Responder<'r, 'r> for NewUser<'r> {
|
||||||
|
fn respond_to(self, _: &'r rocket::Request<'_>) -> response::Result<'r> {
|
||||||
|
let base_response = default_response();
|
||||||
|
let user = self
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|u| format!("{:?}", u))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(",");
|
||||||
|
Response::build()
|
||||||
|
.sized_body(user.len(), Cursor::new(user))
|
||||||
|
.raw_header("X-CUSTOM-ID", "USERS")
|
||||||
|
.join(base_response)
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref USERS: HashMap<&'static str, User> = {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
map.insert(
|
||||||
|
"111-111-111-222-111",
|
||||||
|
User {
|
||||||
|
uuid: String::from("111-111-111-222-111"),
|
||||||
|
name: String::from("JohnDoe"),
|
||||||
|
age: 18,
|
||||||
|
grade: 1,
|
||||||
|
active: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
map.insert(
|
||||||
|
"111-111-111-222-112",
|
||||||
|
User {
|
||||||
|
uuid: String::from("111-111-111-222-112"),
|
||||||
|
name: String::from("JohnDoe2"),
|
||||||
|
age: 20,
|
||||||
|
grade: 2,
|
||||||
|
active: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
map.insert(
|
||||||
|
"111-111-111-222-113",
|
||||||
|
User {
|
||||||
|
uuid: String::from("111-111-111-222-113"),
|
||||||
|
name: String::from("JohnDoe3"),
|
||||||
|
age: 12,
|
||||||
|
grade: 1,
|
||||||
|
active: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
map.insert(
|
||||||
|
"111-111-111-222-114",
|
||||||
|
User {
|
||||||
|
uuid: String::from("111-111-111-222-114"),
|
||||||
|
name: String::from("JohnDoe4"),
|
||||||
|
age: 20,
|
||||||
|
grade: 1,
|
||||||
|
active: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
map.insert(
|
||||||
|
"111-111-111-222-115",
|
||||||
|
User {
|
||||||
|
uuid: String::from("111-111-111-222-115"),
|
||||||
|
name: String::from("JohnDoe5"),
|
||||||
|
age: 18,
|
||||||
|
grade: 1,
|
||||||
|
active: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
map.insert(
|
||||||
|
"111-111-111-222-116",
|
||||||
|
User {
|
||||||
|
uuid: String::from("111-111-111-222-116"),
|
||||||
|
name: String::from("JohnDoe6"),
|
||||||
|
age: 19,
|
||||||
|
grade: 3,
|
||||||
|
active: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
map.insert(
|
||||||
|
"111-111-111-222-117",
|
||||||
|
User {
|
||||||
|
uuid: String::from("111-111-111-222-117"),
|
||||||
|
name: String::from("JohnDoe7"),
|
||||||
|
age: 19,
|
||||||
|
grade: 2,
|
||||||
|
active: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
map.insert(
|
||||||
|
"111-111-111-222-118",
|
||||||
|
User {
|
||||||
|
uuid: String::from("111-111-111-222-118"),
|
||||||
|
name: String::from("JohnDoe8"),
|
||||||
|
age: 21,
|
||||||
|
grade: 2,
|
||||||
|
active: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
map.insert(
|
||||||
|
"111-111-111-222-119",
|
||||||
|
User {
|
||||||
|
uuid: String::from("111-111-111-222-119"),
|
||||||
|
name: String::from("JohnDoe9"),
|
||||||
|
age: 21,
|
||||||
|
grade: 2,
|
||||||
|
active: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
map
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[route(GET,uri = "/user/<uuid>", rank = 1, format = "text/plain")]
|
||||||
|
fn user(uuid: &str) -> Result<&User, Status> {
|
||||||
|
USERS.get(uuid).ok_or(Status::NotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NameGrade<'r> {
|
||||||
|
name: &'r str,
|
||||||
|
grade: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> FromParam<'r> for NameGrade<'r> {
|
||||||
|
type Error = &'static str;
|
||||||
|
fn from_param(param: &'r str) -> Result<Self, Self::Error> {
|
||||||
|
const ERORR_MESSAGE: Result<NameGrade, &'static str> = Err("Error parting user parameter");
|
||||||
|
let name_grade_vec: Vec<&'r str> = param.split("_").collect();
|
||||||
|
match name_grade_vec.len() {
|
||||||
|
2 => match name_grade_vec[1].parse::<u8>() {
|
||||||
|
Ok(n) => Ok(Self {
|
||||||
|
name: name_grade_vec[0],
|
||||||
|
grade: n,
|
||||||
|
}),
|
||||||
|
Err(_) => ERORR_MESSAGE,
|
||||||
|
},
|
||||||
|
_ => ERORR_MESSAGE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[route(GET, uri = "/users/<name_grade>?<filters..>")]
|
||||||
|
fn users(name_grade: NameGrade, filters: Option<Filters>) -> Result<NewUser, Status> {
|
||||||
|
let users: Vec<&User> = USERS
|
||||||
|
.values()
|
||||||
|
.filter(|user| user.name.contains(&name_grade.name) && user.grade == name_grade.grade)
|
||||||
|
.filter(|user| {
|
||||||
|
if let Some(fts) = &filters {
|
||||||
|
user.age == fts.age && user.active == fts.active
|
||||||
|
} else { true }
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
if users.len() > 0 {
|
||||||
|
Ok(NewUser(users))
|
||||||
|
} else {
|
||||||
|
Err(Status::Forbidden)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/favicon.png")]
|
||||||
|
async fn favicon() -> NamedFile {
|
||||||
|
NamedFile::open(Path::new(relative!("static")).join("favicon.png")).await.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[catch(403)]
|
||||||
|
fn forbidden(req: &Request) -> String {
|
||||||
|
format!("Access forbidden {}.", req.uri())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[catch(404)]
|
||||||
|
fn not_found(req: &Request) -> String {
|
||||||
|
format!("We cannot find this page {}.", req.uri())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[launch]
|
||||||
|
fn rocket() -> Rocket<Build> {
|
||||||
|
rocket::build()
|
||||||
|
.mount("/", routes![user, users, favicon])
|
||||||
|
.register("/", catchers![not_found, forbidden])
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user