-
-
Notifications
You must be signed in to change notification settings - Fork 209
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature: Validate extracted data from request #168
Comments
I put it here just as a temporary workaround I found useful. A validated alternative to the existed Wrapping the raw P.S. In the workaround P.P.S. Tested only with Implementationuse salvo::{
async_trait,
extract::Metadata,
http::ParseError,
oapi::{Components, Content, Operation, RequestBody, ToRequestBody},
prelude::{EndpointArgRegister, ToSchema},
Extractible, Request,
};
use serde::{Deserialize, Deserializer};
use std::ops::{Deref, DerefMut};
pub struct JsonValidatedBody<T>(pub T);
impl<T> JsonValidatedBody<T> {
/// Consumes self and returns the value of the parameter.
pub fn into_inner(self) -> T {
self.0
}
}
#[async_trait]
impl<'de, T: validator::Validate> Extractible<'de> for JsonValidatedBody<T>
where
T: Deserialize<'de> + Send,
{
fn metadata() -> &'de Metadata {
static METADATA: Metadata = Metadata::new("");
&METADATA
}
async fn extract(req: &'de mut Request) -> Result<Self, ParseError> {
let res: Self = req.parse_json().await?;
res.0.validate().map_err(ParseError::other)?;
Ok(res)
}
async fn extract_with_arg(req: &'de mut Request, _arg: &str) -> Result<Self, ParseError> {
let res = Self::extract(req).await?;
res.0.validate().map_err(ParseError::other)?;
Ok(res)
}
}
impl<'de, T> Deserialize<'de> for JsonValidatedBody<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize(deserializer).map(JsonValidatedBody)
}
}
impl<'de, T> EndpointArgRegister for JsonValidatedBody<T>
where
T: Deserialize<'de> + ToSchema,
{
fn register(components: &mut Components, operation: &mut Operation, _arg: &str) {
let request_body = Self::to_request_body(components);
let _ = <T as ToSchema>::to_schema(components);
operation.request_body = Some(request_body);
}
}
impl<'de, T> ToRequestBody for JsonValidatedBody<T>
where
T: Deserialize<'de> + ToSchema,
{
fn to_request_body(components: &mut Components) -> RequestBody {
RequestBody::new()
.description("Extract json format data from request.")
.add_content("application/json", Content::new(T::to_schema(components)))
}
}
impl<T> Deref for JsonValidatedBody<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for JsonValidatedBody<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
} Usage#[derive(Deserialize, Validate)]
struct MyObject;
#[handler]
async fn handle(body: JsonValidatedBody <MyObject>) -> String { format!("OK") } |
更新至
|
请更新至最新版本 rust, 如果还是出错,麻烦给出最小重现的例子,谢谢。 |
@chrislearn
|
去除掉上面的 #[async_trait] #[async_trait]
impl<'de, T: validator::Validate> Extractible<'de> for JsonValidatedBody<T> |
Did you guys fix I still have it From the zip
|
This is broken, trying to validate this
I get the trait bound |
I'm using the code below, but I'm not getting compilation errors. If you do encounter a compilation error, please provide a minimal reproducible code base. I cannot run the code you gave above directly. use salvo::oapi::extract::*;
use salvo::prelude::*;
use serde::{Serialize, Deserialize};
use validator::Validate;
#[derive(Serialize, Deserialize, Debug, ToSchema, ToResponse, Validate)]
#[salvo(extract(default_source(from = "body")))]
pub struct Input {
#[validate(length(min = 50))]
#[salvo(schema(max_length = 50, min_length = 2, pattern = "[a-z0-9 ]*"))]
pub new_name: Option<String>,
pub group_id: String,
}
/// Fetch message for a group
#[endpoint(tags("Messages"))]
pub async fn hello(
input: JsonBody<Input>,
) -> String{
"".into()
}
#[tokio::main]
async fn main() {
tracing_subscriber::fmt().init();
let router = Router::new().push(Router::with_path("hello").get(hello));
let doc = OpenApi::new("test api", "0.0.1").merge_router(&router);
let router = router
.unshift(doc.into_router("/api-doc/openapi.json"))
.unshift(SwaggerUi::new("/api-doc/openapi.json").into_router("/swagger-ui"));
let acceptor = TcpListener::new("0.0.0.0:5800").bind().await;
Server::new(acceptor).serve(router).await;
} |
@chrislearn is it possible to use the salvo macro property instead of labeling it twice? |
Now you do need to write it twice. Perhaps verification-related functions will be implemented in future versions and there is no need to write it twice. |
@chrislearn would be super nice not to write it twice and manually check :-D thanks for reply. |
Hope you don't mind me posting this drop of knowledge: For more info, please see this comment: serde-rs/serde#939 (comment) and the following comment, both referring to: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ Hope this helps! |
No description provided.
The text was updated successfully, but these errors were encountered: