From ec9172b1454cc43fe7b2cfd971bbc3f2f5641cdb Mon Sep 17 00:00:00 2001 From: "John D. Corbett" Date: Fri, 17 Jun 2022 17:26:10 -0700 Subject: [PATCH 1/3] Parse and populate route parameters. --- examples/hello-world/api.toml | 1 + src/request.rs | 6 ++-- src/route.rs | 52 ++++++++++++++++++++++++++++++----- 3 files changed, 49 insertions(+), 10 deletions(-) diff --git a/examples/hello-world/api.toml b/examples/hello-world/api.toml index 9d368262..1d36aab9 100644 --- a/examples/hello-world/api.toml +++ b/examples/hello-world/api.toml @@ -1,3 +1,4 @@ [route.greeting] PATH = ["greeting", "greeting/:name"] +":name" = "Literal" diff --git a/src/request.rs b/src/request.rs index 189f1eaf..5ea733c2 100644 --- a/src/request.rs +++ b/src/request.rs @@ -89,7 +89,7 @@ pub enum RequestParamType { #[derive(Clone, Debug)] pub struct RequestParam { - name: String, - param_type: RequestParamType, - required: bool, + pub name: String, + pub param_type: RequestParamType, + pub required: bool, } diff --git a/src/route.rs b/src/route.rs index 1db36aa0..2f4c0fbb 100644 --- a/src/route.rs +++ b/src/route.rs @@ -1,15 +1,17 @@ use crate::{ healthcheck::HealthCheck, - request::{RequestParam, RequestParams}, + request::{RequestParam, RequestParamType, RequestParams}, }; use async_trait::async_trait; use futures::Future; use serde::Serialize; use snafu::Snafu; +use std::collections::HashMap; use std::convert::Infallible; use std::fmt::{self, Display, Formatter}; use std::marker::PhantomData; use std::pin::Pin; +use std::str::FromStr; use tide::{ http::{ self, @@ -19,7 +21,6 @@ use tide::{ }, Body, }; -use tracing::info; /// An error returned by a route handler. /// @@ -146,17 +147,54 @@ pub struct Route { } #[derive(Clone, Debug, Snafu)] -pub enum RouteParseError {} +pub enum RouteParseError { + MissingPathArray, + PathElementError, + InvalidTypeExpression, + UnrecognizedType, +} impl Route { /// Parse a [Route] from a TOML specification. pub fn new(name: String, spec: &toml::Value) -> Result { - // TODO this should be try_into... - info!("name: {}", name); - info!("spec: {:?}", spec); + let paths: Vec = spec["PATH"] + .as_array() + .ok_or(RouteParseError::MissingPathArray)? + .iter() + .map(|v| { + v.as_str() + .ok_or(RouteParseError::PathElementError) + .unwrap() + .to_string() + }) + .collect(); + let mut pmap = HashMap::::new(); + for path in paths.iter() { + for seg in path.split('/') { + if seg.starts_with(':') { + let ptype = RequestParamType::from_str( + spec[seg] + .as_str() + .ok_or(RouteParseError::InvalidTypeExpression)?, + ) + .map_err(|_| RouteParseError::UnrecognizedType)?; + // TODO Should the map key and name be different? If + // not, then RequestParam::name is redundant. + pmap.insert( + seg.to_string(), + RequestParam { + name: seg.to_string(), + param_type: ptype, + // TODO How should we encode optioanl params? + required: true, + }, + ); + } + } + } Ok(Route { name, - patterns: Default::default(), + patterns: paths, params: Default::default(), method: http::Method::Get, doc: String::new(), From e5980c7d52df4100a1e3c718fd27826456cea863 Mon Sep 17 00:00:00 2001 From: "John D. Corbett" Date: Fri, 17 Jun 2022 17:57:26 -0700 Subject: [PATCH 2/3] Resolve conflicts with https://github.com/EspressoSystems/tide-disco/pull/31 --- examples/hello-world/api.toml | 6 ++++- src/route.rs | 48 ++++++++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/examples/hello-world/api.toml b/examples/hello-world/api.toml index 1d36aab9..751fd892 100644 --- a/examples/hello-world/api.toml +++ b/examples/hello-world/api.toml @@ -1,4 +1,8 @@ [route.greeting] -PATH = ["greeting", "greeting/:name"] +PATH = ["greeting/:name"] ":name" = "Literal" +[route.setgreeting] +PATH = ["greeting/:greeting"] +METHOD = "POST" +":greeting" = "Literal" diff --git a/src/route.rs b/src/route.rs index 2f4c0fbb..9a1dd45d 100644 --- a/src/route.rs +++ b/src/route.rs @@ -6,6 +6,7 @@ use async_trait::async_trait; use futures::Future; use serde::Serialize; use snafu::Snafu; +use snafu::{OptionExt, Snafu}; use std::collections::HashMap; use std::convert::Infallible; use std::fmt::{self, Display, Formatter}; @@ -152,6 +153,12 @@ pub enum RouteParseError { PathElementError, InvalidTypeExpression, UnrecognizedType, + MethodMustBeString, + InvalidMethod, + MissingPath, + IncorrectPathType, + IncorrectParamType, + RouteMustBeTable, } impl Route { @@ -194,9 +201,44 @@ impl Route { } Ok(Route { name, - patterns: paths, - params: Default::default(), - method: http::Method::Get, + patterns: match spec.get("PATH").context(MissingPathSnafu)? { + toml::Value::String(s) => vec![s.clone()], + toml::Value::Array(paths) => paths + .iter() + .map(|path| Ok(path.as_str().context(IncorrectPathTypeSnafu)?.to_string())) + .collect::>()?, + _ => return Err(RouteParseError::IncorrectPathType), + }, + params: spec + .as_table() + .context(RouteMustBeTableSnafu)? + .iter() + .filter_map(|(key, val)| { + if !key.starts_with(':') { + return None; + } + let ty = match val.as_str() { + Some(ty) => match ty.parse() { + Ok(ty) => ty, + Err(_) => return Some(Err(RouteParseError::IncorrectParamType)), + }, + None => return Some(Err(RouteParseError::IncorrectParamType)), + }; + Some(Ok(RequestParam { + name: key[1..].to_string(), + param_type: ty, + required: true, + })) + }) + .collect::>()?, + method: match spec.get("METHOD") { + Some(val) => val + .as_str() + .context(MethodMustBeStringSnafu)? + .parse() + .map_err(|_| RouteParseError::InvalidMethod)?, + None => Method::Get, + }, doc: String::new(), handler: None, }) From 636f453a45e3f1fc6c36f139325019a29de1acb6 Mon Sep 17 00:00:00 2001 From: "John D. Corbett" Date: Fri, 17 Jun 2022 18:02:20 -0700 Subject: [PATCH 3/3] Second try at resolving conflicts. --- src/route.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/route.rs b/src/route.rs index 9a1dd45d..ce27b53c 100644 --- a/src/route.rs +++ b/src/route.rs @@ -5,7 +5,6 @@ use crate::{ use async_trait::async_trait; use futures::Future; use serde::Serialize; -use snafu::Snafu; use snafu::{OptionExt, Snafu}; use std::collections::HashMap; use std::convert::Infallible; @@ -237,7 +236,7 @@ impl Route { .context(MethodMustBeStringSnafu)? .parse() .map_err(|_| RouteParseError::InvalidMethod)?, - None => Method::Get, + None => http::Method::Get, }, doc: String::new(), handler: None,