Skip to content
This repository has been archived by the owner on Apr 25, 2023. It is now read-only.

Commit

Permalink
Handle many methods with different params.
Browse files Browse the repository at this point in the history
  • Loading branch information
tomusdrw committed Sep 11, 2017
1 parent 77980b9 commit dc9ec3e
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 43 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ For more see [examples folder](./examples).
# TODO

## General
- [ ] `get_*()` for dynamic params.
- [ ] Auto handle HEAD requests.
- [ ] CORS support
- [ ] Middlewares
Expand Down
53 changes: 44 additions & 9 deletions examples/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,38 @@ extern crate resty;
#[macro_use]
extern crate serde_derive;

use std::sync::RwLock;
use futures::Future;

#[derive(Default)]
struct Products {
calls: Vec<Call>,
calls: RwLock<Vec<Call>>,
}

impl Products {
pub fn list(&self) -> Result<Vec<Call>, resty::Error> {
Ok(self.calls.clone())
Ok(self.calls.read().unwrap().clone())
}

pub fn single(&self, id: usize) -> Result<Call, resty::Error> {
if id < self.calls.len() {
Ok(self.calls[id].clone())
let calls = self.calls.read().unwrap();
if id < calls.len() {
Ok(calls[id].clone())
} else {
Err(resty::Error::not_found(""))
}
}

pub fn add(&self, call: Call) -> Result<Call, resty::Error> {
self.calls.write().unwrap().push(call.clone());
Ok(call)
}

pub fn update(&self, id: usize, call: Call) -> Result<Call, resty::Error> {
let mut calls = self.calls.write().unwrap();
if id < calls.len() {
calls[id] = call.clone();
Ok(call)
} else {
Err(resty::Error::not_found(""))
}
Expand All @@ -36,16 +53,34 @@ impl Into<resty::Router> for Products {
a.list()
});

let a = self_.clone();
// dynamic params
router.get("/{id}", move |request| {
a.single(request.params().get_usize("id")?)
});

let a = self_.clone();
// static params
router.get(url!(/test/{id:usize}), move |request| {
a.single(request.params().id)
});

let a = self_.clone();
// dynamic params
router.get("/dyn/{id}", move |request| {
a.single(request.params().get_usize("id")?)
router.put(url!(/{id:usize}), move |request| {
let a = a.clone();
let id = request.params().id;
request.json().map_err(Into::into).and_then(move |call: Call| {
a.update(id, call)
})
});

let a = self_.clone();
// post request
router.post("/", move |request| {
let a = a.clone();
request.json().map_err(Into::into).and_then(move |call: Call| {
a.add(call)
})
});

router
Expand All @@ -60,12 +95,12 @@ struct Call {
fn main() {
let mut v1 = resty::Router::new();
v1.add("/products", Products {
calls: vec![Call { test: 1 }, Call { test: 2}],
calls: RwLock::new(vec![Call { test: 1 }, Call { test: 2}]),
}.into());

let mut server = resty::Router::new();
server.add("/v1", v1);
server.get("/test", |request| {
server.post("/test", |request| {
request.json().map(|mut call: Call| {
call.test += 1;
call
Expand Down
25 changes: 11 additions & 14 deletions src/request/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ impl<'a> Into<Params<'a>> for &'a str {
match self.find('{') {
None => {
Params {
parser: StdParser::params(""),
parser: StdParser::default(),
prefix: self,
}
},
Expand Down Expand Up @@ -82,11 +82,15 @@ pub trait Parser: Send + Sync + 'static {
/// Returned Parameters type.
type Params;

/// Returns number of expected params and param names.
fn expected_params(&self) -> (usize, String);

/// Parser URL and return params
fn parse(&self, uri: &hyper::Uri, skip: usize) -> Result<Self::Params, Error>;
}

/// A standard parser which processes params dynamically.
#[derive(Debug, Default)]
pub struct StdParser {
params: Vec<(usize, String)>,
segments: Vec<(usize, String)>,
Expand Down Expand Up @@ -121,6 +125,11 @@ impl StdParser {
}
impl Parser for StdParser {
type Params = DynamicParams;

fn expected_params(&self) -> (usize, String) {
(self.expected, self.params.iter().fold(String::new(), |acc, param| acc + "/{" + &param.1 + "}"))
}

fn parse(&self, uri: &hyper::Uri, skip: usize) -> Result<Self::Params, Error> {
let path = &uri.path()[skip..];
if self.expected == 0 && !path.is_empty() {
Expand All @@ -130,7 +139,6 @@ impl Parser for StdParser {
self.params.clone(),
self.segments.clone(),
path.into(),
self.expected,
)
}
}
Expand All @@ -144,7 +152,7 @@ pub struct DynamicParams {

impl DynamicParams {
/// Create new dynamic params and validate segment positions.
pub fn validate(params: Vec<(usize, String)>, segments: Vec<(usize, String)>, path: String, expected: usize) -> Result<Self, Error> {
pub fn validate(params: Vec<(usize, String)>, segments: Vec<(usize, String)>, path: String) -> Result<Self, Error> {
{
let mut it = path.split('/');
let mut current_pos = 0;
Expand All @@ -166,17 +174,6 @@ impl DynamicParams {
None => return Err(Error::NotFound),
}
}

while current_pos < expected {
if it.next().is_none() {
return Err(Error::NotFound);
}
current_pos += 1;
}

if it.next().is_some() {
return Err(Error::NotFound);
}
}

Ok(DynamicParams {
Expand Down
23 changes: 23 additions & 0 deletions src/request/url_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ macro_rules! url_internal {
impl $crate::request::params::Parser for MyParams {
type Params = MyParams;

fn expected_params(&self) -> (usize, String) {
let mut count = 0;
let mut s = String::new();
printer!(count, s, $($data)*);
(count, s)
}

fn parse(&self, uri: &$crate::Uri, skip: usize) -> Result<Self::Params, $crate::request::params::Error> {
let mut it = uri.path()[skip..].split('/');
parser!(it, $($data)*);
Expand Down Expand Up @@ -110,6 +117,22 @@ macro_rules! parser {
};
}

#[doc(hidden)]
#[macro_export]
macro_rules! printer {
($count:expr , $s:expr, ) => {};
($count:expr, $s:expr, segment $x:ident , $($tail:tt)*) => {
$count += 1;
$s += concat!("/", stringify!($x));
printer!($count, $s, $($tail)*);
};
($count:expr, $s:expr, param $param:ident , $($tail:tt)*) => {
$count += 1;
$s += concat!("/{", stringify!($param), "}");
printer!($count, $s, $($tail)*);
};
}

#[test]
fn url_parser() {
use request::params::Parser;
Expand Down
Loading

0 comments on commit dc9ec3e

Please sign in to comment.