Add failure recovery to web package
This commit is contained in:
parent
67d6289d0e
commit
4eca618b77
7 changed files with 204 additions and 25 deletions
|
@ -1,2 +1,4 @@
|
|||
// Specifies how many subqueries will be processed recursively before the query fails.
|
||||
pub const MAX_RECURSIVE_QUERIES: usize = 16;
|
||||
|
||||
pub const APP_ENDPOINT: &'static str = "https://app.surrealdb.com";
|
||||
|
|
|
@ -147,3 +147,5 @@ pub enum Error {
|
|||
#[error("CBOR Error: {0}")]
|
||||
CborError(#[from] CborError),
|
||||
}
|
||||
|
||||
impl warp::reject::Reject for Error {}
|
||||
|
|
108
src/web/fail.rs
Normal file
108
src/web/fail.rs
Normal file
|
@ -0,0 +1,108 @@
|
|||
use crate::err::Error;
|
||||
use serde::Serialize;
|
||||
use warp::http::StatusCode;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Message {
|
||||
code: u16,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
details: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
description: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
information: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn recover(err: warp::Rejection) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
if err.is_not_found() {
|
||||
Ok(warp::reply::with_status(
|
||||
warp::reply::json(&Message {
|
||||
code: 404,
|
||||
details: Some(format!("Requested resource not found")),
|
||||
description: Some(format!("The requested resource does not exist. Check that you have entered the url correctly.")),
|
||||
information: None,
|
||||
}),
|
||||
StatusCode::NOT_FOUND,
|
||||
))
|
||||
} else if let Some(err) = err.find::<Error>() {
|
||||
Ok(warp::reply::with_status(
|
||||
warp::reply::json(&Message {
|
||||
code: 400,
|
||||
details: Some(format!("Request problems detected")),
|
||||
description: Some(format!("There is a problem with your request. Refer to the documentation for further information.")),
|
||||
information: Some(err.to_string()),
|
||||
}),
|
||||
StatusCode::BAD_REQUEST,
|
||||
))
|
||||
} else if let Some(_) = err.find::<warp::reject::MethodNotAllowed>() {
|
||||
Ok(warp::reply::with_status(
|
||||
warp::reply::json(&Message {
|
||||
code: 405,
|
||||
details: Some(format!("Request content length too large")),
|
||||
description: Some(format!("The requested http method is not allowed for this resource. Refer to the documentation for allowed methods.")),
|
||||
information: None,
|
||||
}),
|
||||
StatusCode::METHOD_NOT_ALLOWED,
|
||||
))
|
||||
} else if let Some(_) = err.find::<warp::reject::PayloadTooLarge>() {
|
||||
Ok(warp::reply::with_status(
|
||||
warp::reply::json(&Message {
|
||||
code: 413,
|
||||
details: Some(format!("Request problems detected")),
|
||||
description: Some(format!("The request has exceeded the maximum payload size. Refer to the documentation for the request limitations.")),
|
||||
information: None,
|
||||
}),
|
||||
StatusCode::PAYLOAD_TOO_LARGE,
|
||||
))
|
||||
} else if let Some(_) = err.find::<warp::reject::UnsupportedMediaType>() {
|
||||
Ok(warp::reply::with_status(
|
||||
warp::reply::json(&Message {
|
||||
code: 415,
|
||||
details: Some(format!("Unsupported content type requested")),
|
||||
description: Some(format!("The request needs to adhere to certain constraints. Refer to the documentation for supported content types.")),
|
||||
information: None,
|
||||
}),
|
||||
StatusCode::UNSUPPORTED_MEDIA_TYPE,
|
||||
))
|
||||
} else if let Some(_) = err.find::<warp::reject::MissingHeader>() {
|
||||
Ok(warp::reply::with_status(
|
||||
warp::reply::json(&Message {
|
||||
code: 412,
|
||||
details: Some(format!("Request problems detected")),
|
||||
description: Some(format!("The request appears to be missing a required header. Refer to the documentation for request requirements.")),
|
||||
information: None,
|
||||
}),
|
||||
StatusCode::PRECONDITION_FAILED,
|
||||
))
|
||||
} else if let Some(_) = err.find::<warp::reject::InvalidQuery>() {
|
||||
Ok(warp::reply::with_status(
|
||||
warp::reply::json(&Message {
|
||||
code: 501,
|
||||
details: Some(format!("Not Implemented")),
|
||||
description: Some(format!("The server either does not recognize the request method, or it lacks the ability to fulfill the request.")),
|
||||
information: None,
|
||||
}),
|
||||
StatusCode::NOT_IMPLEMENTED,
|
||||
))
|
||||
} else if let Some(_) = err.find::<warp::reject::InvalidHeader>() {
|
||||
Ok(warp::reply::with_status(
|
||||
warp::reply::json(&Message {
|
||||
code: 501,
|
||||
details: Some(format!("Not Implemented")),
|
||||
description: Some(format!("The server either does not recognize the request method, or it lacks the ability to fulfill the request.")),
|
||||
information: None,
|
||||
}),
|
||||
StatusCode::NOT_IMPLEMENTED,
|
||||
))
|
||||
} else {
|
||||
Ok(warp::reply::with_status(
|
||||
warp::reply::json(&Message {
|
||||
code: 500,
|
||||
details: Some(format!("Internal server error")),
|
||||
description: Some(format!("There was a problem with our servers, and we have been notified. Refer to the documentation for further information")),
|
||||
information: None,
|
||||
}),
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
))
|
||||
}
|
||||
}
|
|
@ -32,6 +32,8 @@ pub fn config() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejecti
|
|||
let base = warp::any();
|
||||
// Get session config
|
||||
let base = base.and(conf::build());
|
||||
// Get content type header
|
||||
let base = base.and(warp::header::<String>(http::header::CONTENT_TYPE.as_str()));
|
||||
// Set base path for all
|
||||
let base = base.and(path!("key" / String).and(warp::path::end()));
|
||||
// Set select method
|
||||
|
@ -55,6 +57,8 @@ pub fn config() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejecti
|
|||
let base = warp::any();
|
||||
// Get session config
|
||||
let base = base.and(conf::build());
|
||||
// Get content type header
|
||||
let base = base.and(warp::header::<String>(http::header::CONTENT_TYPE.as_str()));
|
||||
// Set base path for one
|
||||
let base = base.and(path!("key" / String / String).and(warp::path::end()));
|
||||
// Set select method
|
||||
|
@ -96,6 +100,7 @@ pub fn config() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejecti
|
|||
|
||||
async fn select_all(
|
||||
session: Session,
|
||||
output: String,
|
||||
table: String,
|
||||
query: Query,
|
||||
) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
|
@ -106,12 +111,19 @@ async fn select_all(
|
|||
);
|
||||
let mut vars = HashMap::new();
|
||||
vars.insert(String::from("table"), Value::from(table));
|
||||
let res = crate::dbs::execute(sql.as_str(), session, Some(vars)).await.unwrap();
|
||||
Ok(warp::reply::json(&res))
|
||||
match crate::dbs::execute(sql.as_str(), session, Some(vars)).await {
|
||||
Ok(res) => match output.as_ref() {
|
||||
"application/json" => Ok(warp::reply::json(&res)),
|
||||
"application/cbor" => Ok(warp::reply::json(&res)),
|
||||
_ => Err(warp::reject::not_found()),
|
||||
},
|
||||
Err(err) => Err(warp::reject::custom(err)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn create_all(
|
||||
session: Session,
|
||||
output: String,
|
||||
table: String,
|
||||
body: Bytes,
|
||||
) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
|
@ -122,19 +134,35 @@ async fn create_all(
|
|||
let mut vars = HashMap::new();
|
||||
vars.insert(String::from("table"), Value::from(table));
|
||||
vars.insert(String::from("data"), Value::from(data));
|
||||
let res = crate::dbs::execute(sql, session, Some(vars)).await.unwrap();
|
||||
Ok(warp::reply::json(&res))
|
||||
match crate::dbs::execute(sql, session, Some(vars)).await {
|
||||
Ok(res) => match output.as_ref() {
|
||||
"application/json" => Ok(warp::reply::json(&res)),
|
||||
"application/cbor" => Ok(warp::reply::json(&res)),
|
||||
_ => Err(warp::reject::not_found()),
|
||||
},
|
||||
Err(err) => Err(warp::reject::custom(err)),
|
||||
}
|
||||
}
|
||||
Err(_) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn delete_all(session: Session, table: String) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
async fn delete_all(
|
||||
session: Session,
|
||||
output: String,
|
||||
table: String,
|
||||
) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
let sql = "DELETE type::table($table)";
|
||||
let mut vars = HashMap::new();
|
||||
vars.insert(String::from("table"), Value::from(table));
|
||||
let res = crate::dbs::execute(sql, session, Some(vars)).await.unwrap();
|
||||
Ok(warp::reply::json(&res))
|
||||
match crate::dbs::execute(sql, session, Some(vars)).await {
|
||||
Ok(res) => match output.as_ref() {
|
||||
"application/json" => Ok(warp::reply::json(&res)),
|
||||
"application/cbor" => Ok(warp::reply::json(&res)),
|
||||
_ => Err(warp::reject::not_found()),
|
||||
},
|
||||
Err(err) => Err(warp::reject::custom(err)),
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
|
@ -143,6 +171,7 @@ async fn delete_all(session: Session, table: String) -> Result<impl warp::Reply,
|
|||
|
||||
async fn select_one(
|
||||
session: Session,
|
||||
output: String,
|
||||
table: String,
|
||||
id: String,
|
||||
) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
|
@ -150,12 +179,19 @@ async fn select_one(
|
|||
let mut vars = HashMap::new();
|
||||
vars.insert(String::from("table"), Value::from(table));
|
||||
vars.insert(String::from("id"), Value::from(id));
|
||||
let res = crate::dbs::execute(sql, session, Some(vars)).await.unwrap();
|
||||
Ok(warp::reply::json(&res))
|
||||
match crate::dbs::execute(sql, session, Some(vars)).await {
|
||||
Ok(res) => match output.as_ref() {
|
||||
"application/json" => Ok(warp::reply::json(&res)),
|
||||
"application/cbor" => Ok(warp::reply::json(&res)),
|
||||
_ => Err(warp::reject::not_found()),
|
||||
},
|
||||
Err(err) => Err(warp::reject::custom(err)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn create_one(
|
||||
session: Session,
|
||||
output: String,
|
||||
table: String,
|
||||
id: String,
|
||||
body: Bytes,
|
||||
|
@ -168,8 +204,14 @@ async fn create_one(
|
|||
vars.insert(String::from("table"), Value::from(table));
|
||||
vars.insert(String::from("id"), Value::from(id));
|
||||
vars.insert(String::from("data"), Value::from(data));
|
||||
let res = crate::dbs::execute(sql, session, Some(vars)).await.unwrap();
|
||||
Ok(warp::reply::json(&res))
|
||||
match crate::dbs::execute(sql, session, Some(vars)).await {
|
||||
Ok(res) => match output.as_ref() {
|
||||
"application/json" => Ok(warp::reply::json(&res)),
|
||||
"application/cbor" => Ok(warp::reply::json(&res)),
|
||||
_ => Err(warp::reject::not_found()),
|
||||
},
|
||||
Err(err) => Err(warp::reject::custom(err)),
|
||||
}
|
||||
}
|
||||
Err(_) => todo!(),
|
||||
}
|
||||
|
@ -177,6 +219,7 @@ async fn create_one(
|
|||
|
||||
async fn update_one(
|
||||
session: Session,
|
||||
output: String,
|
||||
table: String,
|
||||
id: String,
|
||||
body: Bytes,
|
||||
|
@ -189,8 +232,14 @@ async fn update_one(
|
|||
vars.insert(String::from("table"), Value::from(table));
|
||||
vars.insert(String::from("id"), Value::from(id));
|
||||
vars.insert(String::from("data"), Value::from(data));
|
||||
let res = crate::dbs::execute(sql, session, Some(vars)).await.unwrap();
|
||||
Ok(warp::reply::json(&res))
|
||||
match crate::dbs::execute(sql, session, Some(vars)).await {
|
||||
Ok(res) => match output.as_ref() {
|
||||
"application/json" => Ok(warp::reply::json(&res)),
|
||||
"application/cbor" => Ok(warp::reply::json(&res)),
|
||||
_ => Err(warp::reject::not_found()),
|
||||
},
|
||||
Err(err) => Err(warp::reject::custom(err)),
|
||||
}
|
||||
}
|
||||
Err(_) => todo!(),
|
||||
}
|
||||
|
@ -198,6 +247,7 @@ async fn update_one(
|
|||
|
||||
async fn modify_one(
|
||||
session: Session,
|
||||
output: String,
|
||||
table: String,
|
||||
id: String,
|
||||
body: Bytes,
|
||||
|
@ -210,8 +260,14 @@ async fn modify_one(
|
|||
vars.insert(String::from("table"), Value::from(table));
|
||||
vars.insert(String::from("id"), Value::from(id));
|
||||
vars.insert(String::from("data"), Value::from(data));
|
||||
let res = crate::dbs::execute(sql, session, Some(vars)).await.unwrap();
|
||||
Ok(warp::reply::json(&res))
|
||||
match crate::dbs::execute(sql, session, Some(vars)).await {
|
||||
Ok(res) => match output.as_ref() {
|
||||
"application/json" => Ok(warp::reply::json(&res)),
|
||||
"application/cbor" => Ok(warp::reply::json(&res)),
|
||||
_ => Err(warp::reject::not_found()),
|
||||
},
|
||||
Err(err) => Err(warp::reject::custom(err)),
|
||||
}
|
||||
}
|
||||
Err(_) => todo!(),
|
||||
}
|
||||
|
@ -219,6 +275,7 @@ async fn modify_one(
|
|||
|
||||
async fn delete_one(
|
||||
session: Session,
|
||||
output: String,
|
||||
table: String,
|
||||
id: String,
|
||||
) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
|
@ -226,6 +283,12 @@ async fn delete_one(
|
|||
let mut vars = HashMap::new();
|
||||
vars.insert(String::from("table"), Value::from(table));
|
||||
vars.insert(String::from("id"), Value::from(id));
|
||||
let res = crate::dbs::execute(sql, session, Some(vars)).await.unwrap();
|
||||
Ok(warp::reply::json(&res))
|
||||
match crate::dbs::execute(sql, session, Some(vars)).await {
|
||||
Ok(res) => match output.as_ref() {
|
||||
"application/json" => Ok(warp::reply::json(&res)),
|
||||
"application/cbor" => Ok(warp::reply::json(&res)),
|
||||
_ => Err(warp::reject::not_found()),
|
||||
},
|
||||
Err(err) => Err(warp::reject::custom(err)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
mod conf;
|
||||
mod export;
|
||||
mod fail;
|
||||
mod head;
|
||||
mod import;
|
||||
mod key;
|
||||
|
@ -45,6 +46,8 @@ pub async fn init(conf: &clap::ArgMatches) -> Result<(), Error> {
|
|||
.or(sql::config())
|
||||
// API query endpoint
|
||||
.or(key::config())
|
||||
// Catch all errors
|
||||
.recover(fail::recover)
|
||||
// End routes setup
|
||||
;
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use crate::cnf;
|
||||
use warp::http::Uri;
|
||||
use warp::Filter;
|
||||
|
||||
pub fn config() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
|
||||
warp::path::end()
|
||||
.and(warp::get())
|
||||
.map(|| warp::redirect(Uri::from_static("https://app.surrealdb.com")))
|
||||
warp::path::end().and(warp::get()).map(|| warp::redirect(Uri::from_static(cnf::APP_ENDPOINT)))
|
||||
}
|
||||
|
|
|
@ -40,10 +40,12 @@ async fn handler(
|
|||
sql: Bytes,
|
||||
) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
let sql = std::str::from_utf8(&sql).unwrap();
|
||||
let res = crate::dbs::execute(sql, session, None).await.unwrap();
|
||||
match output.as_ref() {
|
||||
match crate::dbs::execute(sql, session, None).await {
|
||||
Ok(res) => match output.as_ref() {
|
||||
"application/json" => Ok(warp::reply::json(&res)),
|
||||
"application/cbor" => Ok(warp::reply::json(&res)),
|
||||
_ => Err(warp::reject::not_found()),
|
||||
},
|
||||
Err(err) => Err(warp::reject::custom(err)),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue