Skip to content
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

Path extractor not working for enums #318

Open
sean-bennett112 opened this issue Jun 15, 2018 · 7 comments · May be fixed by #2881
Open

Path extractor not working for enums #318

sean-bennett112 opened this issue Jun 15, 2018 · 7 comments · May be fixed by #2881
Labels
A-web project: actix-web C-improvement Category: an improvement to existing functionality

Comments

@sean-bennett112
Copy link

It looks like the Path extractor doesn't currently work with enums. To illustrate, I’m getting

 WARN 2018-06-14T23:46:13Z: actix_web::pipeline: Error occured during request handling: unsupported type: 'any'
 INFO 2018-06-14T23:46:13Z: actix_web::middleware::logger: 127.0.0.1:63742 [14/Jun/2018:16:46:13 -0700] "GET /my_resource/52635231 HTTP/1.1" 404 0 "-" "curl/7.54.0” 0.000458

whenever I try to do the following:

.resource(“/my_resource/{thing}", |r| {
    r.method(Method::GET).with(handle_mypath)
})
#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum MyThing {
    String(String),
    Int(u32),
}

pub fn handle_mypath<A>((state, path): (State<Arc<A>>, Path<MyThing>)) -> HttpResponse {}

It appears to never reach the handler, despite compiling fine. As soon as I convert it to a bare type or a struct it seems to work fine. Interestingly, Query extractors seem to work fine with this.

@fafhrd91
Copy link
Member

@DoumanAsh @Dowwie i think this should be fixed with latest serde_urlencoded?

@DoumanAsh
Copy link
Contributor

@fafhrd91 No, Path extract uses own deserializer
I don't see it using seder url encoded, we only can use it for query component of path.
In case of path, we just cannot handle enums at all

@fafhrd91
Copy link
Member

Oh, right

@DoumanAsh DoumanAsh added the C-improvement Category: an improvement to existing functionality label Nov 23, 2018
@rokob
Copy link

rokob commented May 14, 2019

Any update here?

@fafhrd91
Copy link
Member

No updates. I won’t have any time in near future

@robjtede robjtede added the A-web project: actix-web label Nov 2, 2020
@robjtede robjtede self-assigned this Nov 2, 2020
@robjtede robjtede added this to the actix-web v3.3 milestone Nov 2, 2020
@robjtede robjtede removed this from the actix-web v3.3 milestone Nov 27, 2020
@DokkanWiki
Copy link

DokkanWiki commented Jul 2, 2022

Work around:

pub enum ArticleUid {
    String(String),
    Int(u64),
}

impl FromStr for ArticleUid {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(match s.parse::<u64>() {
            Ok(uid) => ArticleUid::Int(uid),
            Err(_) => ArticleUid::String(s.to_string())
        })
    }
}

#[get("/site_news/{uid}")]
pub async fn get_site_article(
    req: HttpRequest
) -> HttpResponse {
    let uid: Option<ArticleUid> = req.match_info().get("uid").and_then(|v| v.parse().ok());
    // ...   
}

@nitn3lav nitn3lav linked a pull request Sep 18, 2022 that will close this issue
5 tasks
@robjtede robjtede removed their assignment Sep 25, 2022
@aliyss
Copy link

aliyss commented Mar 21, 2023

Another workaround so one can actually keep the current structure and still use Path:

I'm new to rust so this may not be the ultimate top code or so... feel free to judge. ❤️

use serde::{Serialize};

/// Make sure you are not using Deserialize here.
#[derive(Debug, Serialize)]
#[serde(untagged)]
pub enum ProjectNameOrId {
    Name(String),
    Id(u64),
}
use serde::{de::Deserializer, Deserialize};
use std::str::FromStr;

// This can be left out if impl Deserialize is adjusted...
// but honestly I had already added it, so I just stuck to it.
impl FromStr for ProjectNameOrId {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Ok(id) = s.parse::<u64>() {
            return Ok(ProjectNameOrId::Id(id));
        }
        Ok(ProjectNameOrId::Name(String::from(s)))
    }
}

impl<'de> Deserialize<'de> for ProjectNameOrId {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        ProjectNameOrId::from_str(&s).map_err(|_| serde::de::Error::custom("invalid ProjectNameOrId value"))
    }
}
use crate::AppState;
use actix_web::{get, web, HttpResponse, Responder};

#[get("/schema")]
async fn get_schema(
    data: web::Data<AppState>,
    path: web::Path<ProjectNameOrId>
) -> impl Responder {
    /* Your Code */
    println!("{:#?}", &path);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-web project: actix-web C-improvement Category: an improvement to existing functionality
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants