1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-30 18:34:36 +01:00

remove Path and Query from public api

This commit is contained in:
Nikolay Kim 2018-03-26 18:18:38 -07:00
parent 052d5f0bc5
commit 8fff2c7595
6 changed files with 84 additions and 28 deletions

View File

@ -2,6 +2,8 @@
## 0.4.11
* Added `HttpReuqest::extract_xxx()`, type safe path/query information extractor.
* Fix long client urls #129
* Fix panic on invalid URL characters #130

View File

@ -5,7 +5,7 @@ and [`ResponseError` trait](../actix_web/error/trait.ResponseError.html)
for handling handler's errors.
Any error that implements `ResponseError` trait can be returned as error value.
*Handler* can return *Result* object, actix by default provides
`Responder` implementation for compatible result object. Here is implementation
`Responder` implementation for compatible result types. Here is implementation
definition:
```rust,ignore
@ -64,7 +64,7 @@ fn index(req: HttpRequest) -> Result<&'static str, MyError> {
# }
```
In this example *index* handler will always return *500* response. But it is easy
In this example *index* handler always returns *500* response. But it is easy
to return different responses for different type of errors.
```rust
@ -109,7 +109,7 @@ fn index(req: HttpRequest) -> Result<&'static str, MyError> {
## Error helpers
Actix provides set of error helper types. It is possible to use them to generate
specific error responses. We can use helper types for first example with custom error.
specific error responses. We can use helper types for the first example with custom error.
```rust
# extern crate actix_web;

View File

@ -13,6 +13,7 @@ use http2::Error as Http2Error;
use http::{header, StatusCode, Error as HttpError};
use http::uri::InvalidUri;
use http_range::HttpRangeParseError;
use serde::de::value::Error as DeError;
use serde_json::error::Error as JsonError;
pub use url::ParseError as UrlParseError;
@ -109,6 +110,13 @@ impl ResponseError for JsonError {}
/// `InternalServerError` for `UrlParseError`
impl ResponseError for UrlParseError {}
/// Return `BAD_REQUEST` for `de::value::Error`
impl ResponseError for DeError {
fn error_response(&self) -> HttpResponse {
HttpResponse::new(StatusCode::BAD_REQUEST, Body::Empty)
}
}
/// Return `InternalServerError` for `HttpError`,
/// Response generation can return `HttpError`, so it is internal error
impl ResponseError for HttpError {}

View File

@ -1,11 +1,10 @@
use serde_urlencoded;
use serde::de::{self, Deserializer, Visitor, Error as DeError};
use error::{Error, ErrorBadRequest};
use httprequest::HttpRequest;
pub trait HttpRequestExtractor<'de> {
fn extract<T, S>(&self, req: &'de HttpRequest<S>) -> Result<T, Error>
fn extract<T, S>(&self, req: &'de HttpRequest<S>) -> Result<T, de::value::Error>
where T: de::Deserialize<'de>, S: 'static;
}
@ -19,6 +18,7 @@ pub trait HttpRequestExtractor<'de> {
/// # extern crate futures;
/// #[macro_use] extern crate serde_derive;
/// use actix_web::*;
/// use actix_web::dev::{Path, HttpRequestExtractor};
///
/// #[derive(Deserialize)]
/// struct Info {
@ -26,7 +26,7 @@ pub trait HttpRequestExtractor<'de> {
/// }
///
/// fn index(mut req: HttpRequest) -> Result<String> {
/// let info: Info = req.extract(Path)?; // <- extract path info using serde
/// let info: Info = Path.extract(&req)?; // <- extract path info using serde
/// Ok(format!("Welcome {}!", info.username))
/// }
///
@ -40,11 +40,10 @@ pub struct Path;
impl<'de> HttpRequestExtractor<'de> for Path {
#[inline]
fn extract<T, S>(&self, req: &'de HttpRequest<S>) -> Result<T, Error>
fn extract<T, S>(&self, req: &'de HttpRequest<S>) -> Result<T, de::value::Error>
where T: de::Deserialize<'de>, S: 'static,
{
Ok(de::Deserialize::deserialize(PathExtractor{req: req})
.map_err(ErrorBadRequest)?)
de::Deserialize::deserialize(PathExtractor{req: req})
}
}
@ -58,6 +57,7 @@ impl<'de> HttpRequestExtractor<'de> for Path {
/// # extern crate futures;
/// #[macro_use] extern crate serde_derive;
/// use actix_web::*;
/// use actix_web::dev::{Query, HttpRequestExtractor};
///
/// #[derive(Deserialize)]
/// struct Info {
@ -65,7 +65,7 @@ impl<'de> HttpRequestExtractor<'de> for Path {
/// }
///
/// fn index(mut req: HttpRequest) -> Result<String> {
/// let info: Info = req.extract(Query)?; // <- extract query info using serde
/// let info: Info = Query.extract(&req)?; // <- extract query info using serde
/// Ok(format!("Welcome {}!", info.username))
/// }
///
@ -75,11 +75,10 @@ pub struct Query;
impl<'de> HttpRequestExtractor<'de> for Query {
#[inline]
fn extract<T, S>(&self, req: &'de HttpRequest<S>) -> Result<T, Error>
fn extract<T, S>(&self, req: &'de HttpRequest<S>) -> Result<T, de::value::Error>
where T: de::Deserialize<'de>, S: 'static,
{
Ok(serde_urlencoded::from_str::<T>(req.query_string())
.map_err(ErrorBadRequest)?)
serde_urlencoded::from_str::<T>(req.query_string())
}
}
@ -189,7 +188,6 @@ impl<'de, S: 'static> Deserializer<'de> for PathExtractor<'de, S>
#[cfg(test)]
mod tests {
use super::*;
use router::{Router, Pattern};
use resource::Resource;
use test::TestRequest;
@ -217,15 +215,15 @@ mod tests {
let (router, _) = Router::new("", ServerSettings::default(), routes);
assert!(router.recognize(&mut req).is_some());
let s: MyStruct = req.extract(Path).unwrap();
let s: MyStruct = req.extract_path().unwrap();
assert_eq!(s.key, "name");
assert_eq!(s.value, "user1");
let s: (String, String) = req.extract(Path).unwrap();
let s: (String, String) = req.extract_path().unwrap();
assert_eq!(s.0, "name");
assert_eq!(s.1, "user1");
let s: Id = req.extract(Query).unwrap();
let s: Id = req.extract_query().unwrap();
assert_eq!(s.id, "test");
}
}

View File

@ -20,7 +20,7 @@ use payload::Payload;
use httpmessage::HttpMessage;
use httpresponse::{HttpResponse, HttpResponseBuilder};
use helpers::SharedHttpInnerMessage;
use extractor::HttpRequestExtractor;
use extractor::{Path, Query, HttpRequestExtractor};
use error::{Error, UrlGenerationError, CookieParseError, PayloadError};
@ -383,6 +383,7 @@ impl<S> HttpRequest<S> {
}
/// Get a reference to the Params object.
///
/// Params is a container for url parameters.
/// Route supports glob patterns: * for a single wildcard segment and :param
/// for matching storing that segment of the request url in the Params object.
@ -397,14 +398,15 @@ impl<S> HttpRequest<S> {
unsafe{ mem::transmute(&mut self.as_mut().params) }
}
/// Extract typed information from path.
/// Extract typed information from request's path.
///
/// By default, in case of error `BAD_REQUEST` response get returned to peer.
/// If you need to return different response use `map_err()` method.
///
/// ## Example
///
/// ```rust
/// # extern crate bytes;
/// # extern crate actix_web;
/// # extern crate futures;
/// #[macro_use] extern crate serde_derive;
/// use actix_web::*;
///
@ -414,8 +416,7 @@ impl<S> HttpRequest<S> {
/// }
///
/// fn index(mut req: HttpRequest) -> Result<String> {
/// let info: Info = req.extract(Path)?; // <- extract path info using serde
/// let info: Info = req.extract(Query)?; // <- extract query info
/// let info: Info = req.extract_path()?; // <- extract path info using serde
/// Ok(format!("Welcome {}!", info.username))
/// }
///
@ -425,12 +426,60 @@ impl<S> HttpRequest<S> {
/// |r| r.method(Method::GET).f(index));
/// }
/// ```
pub fn extract<'a, T, D>(&'a self, ds: D) -> Result<T, Error>
pub fn extract_path<'a, T>(&'a self) -> Result<T, Error>
where S: 'static,
T: de::Deserialize<'a>,
D: HttpRequestExtractor<'a>
{
ds.extract(self)
Ok(Path.extract(self)?)
}
/// Extract typed information from request's query string.
///
/// ## Example
///
/// ```rust
/// # extern crate actix_web;
/// #[macro_use] extern crate serde_derive;
/// use actix_web::{HttpRequest, Result};
///
/// #[derive(Deserialize)]
/// struct Info {
/// username: String,
/// }
///
/// fn index(mut req: HttpRequest) -> Result<String> {
/// let info: Info = req.extract_query()?; // <- extract query info, i.e: /?id=username
/// Ok(format!("Welcome {}!", info.username))
/// }
/// # fn main() {}
/// ```
///
/// By default, in case of error, `BAD_REQUEST` response get returned to peer.
/// If you need to return different response use `map_err()` method.
///
/// ```rust
/// # extern crate actix_web;
/// #[macro_use] extern crate serde_derive;
/// use actix_web::{HttpRequest, Result, error};
///
/// #[derive(Deserialize)]
/// struct Info {
/// username: String,
/// }
///
/// fn index(mut req: HttpRequest) -> Result<String> {
/// let info: Info = req.extract_query() // <- extract query information
/// .map_err(error::ErrorInternalServerError)?; // <- return 500 in case of error
/// Ok(format!("Welcome {}!", info.username))
/// }
/// # fn main() {}
/// ```
///
pub fn extract_query<'a, T>(&'a self) -> Result<T, Error>
where S: 'static,
T: de::Deserialize<'a>,
{
Ok(Query.extract(self)?)
}
/// Checks if a connection should be kept alive.

View File

@ -144,7 +144,6 @@ pub use route::Route;
pub use resource::Resource;
pub use context::HttpContext;
pub use server::HttpServer;
pub use extractor::{Path, Query};
// re-exports
pub use http::{Method, StatusCode, Version};
@ -190,5 +189,5 @@ pub mod dev {
pub use param::{FromParam, Params};
pub use httpmessage::{UrlEncoded, MessageBody};
pub use httpresponse::HttpResponseBuilder;
pub use extractor::HttpRequestExtractor;
pub use extractor::{Path, Query, HttpRequestExtractor};
}