Decode urlencoded path parameters automatically

Closes #1396
This commit is contained in:
Tobie Morgan Hitchcock 2023-01-17 14:10:21 +00:00
parent c37d93bcb9
commit 7682a97a33
4 changed files with 54 additions and 22 deletions

1
Cargo.lock generated
View file

@ -3465,6 +3465,7 @@ dependencies = [
"surrealdb", "surrealdb",
"thiserror", "thiserror",
"tokio", "tokio",
"urlencoding",
"warp", "warp",
] ]

View file

@ -47,6 +47,7 @@ serde_pack = { version = "1.1.1", package = "rmp-serde" }
surrealdb = { path = "lib", features = ["protocol-http", "protocol-ws", "rustls"] } surrealdb = { path = "lib", features = ["protocol-http", "protocol-ws", "rustls"] }
thiserror = "1.0.38" thiserror = "1.0.38"
tokio = { version = "1.24.1", features = ["macros", "signal"] } tokio = { version = "1.24.1", features = ["macros", "signal"] }
urlencoding = "2.1.2"
warp = { version = "0.3.3", features = ["compression", "tls", "websocket"] } warp = { version = "0.3.3", features = ["compression", "tls", "websocket"] }
[package.metadata.deb] [package.metadata.deb]

View file

@ -3,7 +3,7 @@ use crate::dbs::DB;
use crate::err::Error; use crate::err::Error;
use crate::net::input::bytes_to_utf8; use crate::net::input::bytes_to_utf8;
use crate::net::output; use crate::net::output;
use crate::net::params::Params; use crate::net::params::{Param, Params};
use crate::net::session; use crate::net::session;
use bytes::Bytes; use bytes::Bytes;
use serde::Deserialize; use serde::Deserialize;
@ -39,7 +39,7 @@ pub fn config() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejecti
let select = warp::any() let select = warp::any()
.and(warp::get()) .and(warp::get())
.and(warp::header::<String>(http::header::ACCEPT.as_str())) .and(warp::header::<String>(http::header::ACCEPT.as_str()))
.and(path!("key" / String).and(warp::path::end())) .and(path!("key" / Param).and(warp::path::end()))
.and(warp::query()) .and(warp::query())
.and(session::build()) .and(session::build())
.and_then(select_all); .and_then(select_all);
@ -47,7 +47,7 @@ pub fn config() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejecti
let create = warp::any() let create = warp::any()
.and(warp::post()) .and(warp::post())
.and(warp::header::<String>(http::header::ACCEPT.as_str())) .and(warp::header::<String>(http::header::ACCEPT.as_str()))
.and(path!("key" / String).and(warp::path::end())) .and(path!("key" / Param).and(warp::path::end()))
.and(warp::body::content_length_limit(MAX)) .and(warp::body::content_length_limit(MAX))
.and(warp::body::bytes()) .and(warp::body::bytes())
.and(warp::query()) .and(warp::query())
@ -57,7 +57,7 @@ pub fn config() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejecti
let delete = warp::any() let delete = warp::any()
.and(warp::delete()) .and(warp::delete())
.and(warp::header::<String>(http::header::ACCEPT.as_str())) .and(warp::header::<String>(http::header::ACCEPT.as_str()))
.and(path!("key" / String).and(warp::path::end())) .and(path!("key" / Param).and(warp::path::end()))
.and(warp::query()) .and(warp::query())
.and(session::build()) .and(session::build())
.and_then(delete_all); .and_then(delete_all);
@ -72,14 +72,14 @@ pub fn config() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejecti
let select = warp::any() let select = warp::any()
.and(warp::get()) .and(warp::get())
.and(warp::header::<String>(http::header::ACCEPT.as_str())) .and(warp::header::<String>(http::header::ACCEPT.as_str()))
.and(path!("key" / String / String).and(warp::path::end())) .and(path!("key" / Param / Param).and(warp::path::end()))
.and(session::build()) .and(session::build())
.and_then(select_one); .and_then(select_one);
// Set create method // Set create method
let create = warp::any() let create = warp::any()
.and(warp::post()) .and(warp::post())
.and(warp::header::<String>(http::header::ACCEPT.as_str())) .and(warp::header::<String>(http::header::ACCEPT.as_str()))
.and(path!("key" / String / String).and(warp::path::end())) .and(path!("key" / Param / Param).and(warp::path::end()))
.and(warp::body::content_length_limit(MAX)) .and(warp::body::content_length_limit(MAX))
.and(warp::body::bytes()) .and(warp::body::bytes())
.and(warp::query()) .and(warp::query())
@ -89,7 +89,7 @@ pub fn config() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejecti
let update = warp::any() let update = warp::any()
.and(warp::put()) .and(warp::put())
.and(warp::header::<String>(http::header::ACCEPT.as_str())) .and(warp::header::<String>(http::header::ACCEPT.as_str()))
.and(path!("key" / String / String).and(warp::path::end())) .and(path!("key" / Param / Param).and(warp::path::end()))
.and(warp::body::content_length_limit(MAX)) .and(warp::body::content_length_limit(MAX))
.and(warp::body::bytes()) .and(warp::body::bytes())
.and(warp::query()) .and(warp::query())
@ -99,7 +99,7 @@ pub fn config() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejecti
let modify = warp::any() let modify = warp::any()
.and(warp::patch()) .and(warp::patch())
.and(warp::header::<String>(http::header::ACCEPT.as_str())) .and(warp::header::<String>(http::header::ACCEPT.as_str()))
.and(path!("key" / String / String).and(warp::path::end())) .and(path!("key" / Param / Param).and(warp::path::end()))
.and(warp::body::content_length_limit(MAX)) .and(warp::body::content_length_limit(MAX))
.and(warp::body::bytes()) .and(warp::body::bytes())
.and(warp::query()) .and(warp::query())
@ -109,7 +109,7 @@ pub fn config() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejecti
let delete = warp::any() let delete = warp::any()
.and(warp::delete()) .and(warp::delete())
.and(warp::header::<String>(http::header::ACCEPT.as_str())) .and(warp::header::<String>(http::header::ACCEPT.as_str()))
.and(path!("key" / String / String).and(warp::path::end())) .and(path!("key" / Param / Param).and(warp::path::end()))
.and(warp::query()) .and(warp::query())
.and(session::build()) .and(session::build())
.and_then(delete_one); .and_then(delete_one);
@ -130,7 +130,7 @@ pub fn config() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejecti
async fn select_all( async fn select_all(
output: String, output: String,
table: String, table: Param,
query: Query, query: Query,
session: Session, session: Session,
) -> Result<impl warp::Reply, warp::Rejection> { ) -> Result<impl warp::Reply, warp::Rejection> {
@ -164,7 +164,7 @@ async fn select_all(
async fn create_all( async fn create_all(
output: String, output: String,
table: String, table: Param,
body: Bytes, body: Bytes,
params: Params, params: Params,
session: Session, session: Session,
@ -205,7 +205,7 @@ async fn create_all(
async fn delete_all( async fn delete_all(
output: String, output: String,
table: String, table: Param,
params: Params, params: Params,
session: Session, session: Session,
) -> Result<impl warp::Reply, warp::Rejection> { ) -> Result<impl warp::Reply, warp::Rejection> {
@ -240,8 +240,8 @@ async fn delete_all(
async fn select_one( async fn select_one(
output: String, output: String,
table: String, table: Param,
id: String, id: Param,
session: Session, session: Session,
) -> Result<impl warp::Reply, warp::Rejection> { ) -> Result<impl warp::Reply, warp::Rejection> {
// Get the datastore reference // Get the datastore reference
@ -276,8 +276,8 @@ async fn select_one(
async fn create_one( async fn create_one(
output: String, output: String,
table: String, table: Param,
id: String, id: Param,
body: Bytes, body: Bytes,
params: Params, params: Params,
session: Session, session: Session,
@ -324,8 +324,8 @@ async fn create_one(
async fn update_one( async fn update_one(
output: String, output: String,
table: String, table: Param,
id: String, id: Param,
body: Bytes, body: Bytes,
params: Params, params: Params,
session: Session, session: Session,
@ -372,8 +372,8 @@ async fn update_one(
async fn modify_one( async fn modify_one(
output: String, output: String,
table: String, table: Param,
id: String, id: Param,
body: Bytes, body: Bytes,
params: Params, params: Params,
session: Session, session: Session,
@ -420,8 +420,8 @@ async fn modify_one(
async fn delete_one( async fn delete_one(
output: String, output: String,
table: String, table: Param,
id: String, id: Param,
params: Params, params: Params,
session: Session, session: Session,
) -> Result<impl warp::Reply, warp::Rejection> { ) -> Result<impl warp::Reply, warp::Rejection> {

View file

@ -1,7 +1,37 @@
use crate::err::Error;
use serde::Deserialize; use serde::Deserialize;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::ops::Deref;
use std::str::FromStr;
use surrealdb::sql::Value; use surrealdb::sql::Value;
#[derive(Debug, Clone)]
pub struct Param(pub String);
impl Deref for Param {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
self.0.as_str()
}
}
impl FromStr for Param {
type Err = Error;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = urlencoding::decode(s)?.into_owned();
Ok(Param(s))
}
}
impl From<Param> for Value {
#[inline]
fn from(v: Param) -> Self {
Value::from(v.0)
}
}
#[derive(Default, Deserialize, Debug, Clone)] #[derive(Default, Deserialize, Debug, Clone)]
pub struct Params { pub struct Params {
#[serde(flatten)] #[serde(flatten)]