Make `Request::{body_json, body_form}` call `validate`

This commit is contained in:
Yoshua Wuyts 2020-10-08 00:18:48 +02:00
parent 28be83744b
commit 689ddfbe80
6 changed files with 29 additions and 17 deletions

View File

@ -75,7 +75,8 @@ lazy_static! {
}
async fn handle_graphql(mut request: Request<State>) -> tide::Result {
let query: GraphQLRequest = request.body_json().await?;
let body = request.take_body();
let query: GraphQLRequest = body.into_json().await?;
let response = query.execute(&SCHEMA, request.state());
let status = if response.is_ok() {
StatusCode::Ok

View File

@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
use tide::prelude::*; // Pulls in the json! macro.
use tide::{Body, Request};
#[derive(Deserialize, Serialize)]
#[derive(Deserialize, Serialize, Validate)]
struct Cat {
name: String,
}

View File

@ -23,10 +23,8 @@
//! }
//!
//! async fn order_shoes(mut req: Request<()>) -> tide::Result {
//! let animal: Animal = req.body_json().await?;
//! animal.validate().status(400)?;
//! let msg = format!("Hello, {}! I've put in an order for {} shoes", animal.name, animal.legs);
//! Ok(msg.into())
//! let Animal { name, legs } = req.body_json().await?;
//! Ok(format!("Hello, {}! I've put in an order for {} shoes", name, legs).into())
//! }
//! ```

View File

@ -23,7 +23,7 @@
//! use tide::Request;
//! use tide::prelude::*;
//!
//! #[derive(Debug, Deserialize)]
//! #[derive(Debug, Deserialize, Validate)]
//! struct Animal {
//! name: String,
//! legs: u8,

View File

@ -5,11 +5,12 @@ use route_recognizer::Params;
use std::ops::Index;
use std::pin::Pin;
use crate::convert::Validate;
use crate::cookies::CookieData;
use crate::http::cookies::Cookie;
use crate::http::format_err;
use crate::http::headers::{self, HeaderName, HeaderValues, ToHeaderValues};
use crate::http::{self, Body, Method, Mime, StatusCode, Url, Version};
use crate::http::{self, Body, Method, Mime, Status, StatusCode, Url, Version};
use crate::Response;
pin_project_lite::pin_project! {
@ -433,7 +434,9 @@ impl<State> Request<State> {
Ok(res)
}
/// Reads and deserialized the entire request body via json.
/// Reads, deserializes and validates the entire request body via json.
///
/// Unlike `Body::into_json` this method also validates the request body.
///
/// # Errors
///
@ -442,19 +445,26 @@ impl<State> Request<State> {
///
/// If the body cannot be interpreted as valid json for the target type `T`,
/// an `Err` is returned.
pub async fn body_json<T: serde::de::DeserializeOwned>(&mut self) -> crate::Result<T> {
let res = self.req.body_json().await?;
///
/// If the body cannot be validated, an `Err` is returned.
pub async fn body_json<T: serde::de::DeserializeOwned + Validate>(
&mut self,
) -> crate::Result<T> {
let res: T = self.req.body_json().await?;
res.validate().status(400)?;
Ok(res)
}
/// Parse the request body as a form.
/// Parse the request body as a form and validate it.
///
/// Unlike `Body::into_form` this method also validates the request body.
///
/// ```rust
/// # fn main() -> Result<(), std::io::Error> { async_std::task::block_on(async {
/// use tide::prelude::*;
/// let mut app = tide::new();
///
/// #[derive(Deserialize)]
/// #[derive(Deserialize, Validate)]
/// struct Animal {
/// name: String,
/// legs: u8
@ -479,8 +489,11 @@ impl<State> Request<State> {
/// // number too large to fit in target type
/// # Ok(()) })}
/// ```
pub async fn body_form<T: serde::de::DeserializeOwned>(&mut self) -> crate::Result<T> {
let res = self.req.body_form().await?;
pub async fn body_form<T: serde::de::DeserializeOwned + Validate>(
&mut self,
) -> crate::Result<T> {
let res: T = self.req.body_form().await?;
res.validate().status(400)?;
Ok(res)
}

View File

@ -3,7 +3,7 @@ use async_std::prelude::*;
use async_std::task;
use std::time::Duration;
use serde::{Deserialize, Serialize};
use tide::prelude::*;
use tide::{Body, Request};
#[test]
@ -66,7 +66,7 @@ fn echo_server() -> tide::Result<()> {
#[test]
fn json() -> tide::Result<()> {
#[derive(Deserialize, Serialize)]
#[derive(Deserialize, Serialize, Validate)]
struct Counter {
count: usize,
}