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

Incorrect output when using serde tags #290

Open
madisonbullard opened this issue Nov 15, 2024 · 1 comment
Open

Incorrect output when using serde tags #290

madisonbullard opened this issue Nov 15, 2024 · 1 comment

Comments

@madisonbullard
Copy link

madisonbullard commented Nov 15, 2024

Hello,

I've followed Tauri's suggested error handling implementation, and noticed an issue with specta's parsing of serde tags like so:

#[derive(Debug, thiserror::Error, specta::Type)]
enum Error {
    #[error("io error: {0}")]
    Io(String),
    #[error("failed to parse as string: {0}")]
    Utf8(String),
}

#[derive(serde::Serialize)]
#[serde(tag = "kind", content = "message")]
#[serde(rename_all = "camelCase")]
enum ErrorKind {
    Io(String),
    Utf8(String),
}

impl serde::Serialize for Error {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::ser::Serializer,
    {
        let error_message = self.to_string();
        let error_kind = match self {
            Self::Io(_) => ErrorKind::Io(error_message),
            Self::Utf8(_) => ErrorKind::Utf8(error_message),
        };
        error_kind.serialize(serializer)
    }
}

Here are my deps:

[dependencies]
serde = { version = "1.0.215", features = ["derive"] }
specta = { version = "2.0.0-rc.20", features = ["derive"] }
specta-typescript = "0.0.7"
thiserror = "2.0.3"

Reproduction here

On the left is actual, right is what I expect:

assertion `left == right` failed
  left: "export type Error = { Io: string } | { Utf8: string }"
 right: "export type Error = { kind: \"io\"; message: string } | { kind: \"utf8\"; message: string }".to_string()

I've confirmed that the error comes through to my frontend in the expected shape, but the specta bindings are incorrect. To resolve, I have to add #[serde(tag = "kind", content = "message")] to the Error declaration in addition to the ErrorKind declaration.

Lmk if I can provide any more info. Thanks for a great lib.

@Brendonovich
Copy link
Collaborator

Having to add #[serde(tag = "kind", content = "message")] to Error in addition to ErrorKind is to be expected - Specta only analyses field attributes, it can't know what custom Serialize implementation you have.
One trick you might be able to use is adding derive(Type) to ErrorKind, removing it from Error, then using #[specta(remote = Error)] on ErrorKind:

#[derive(Debug, thiserror::Error)]
enum Error {
    #[error("io error: {0}")]
    Io(String),
    #[error("failed to parse as string: {0}")]
    Utf8(String),
}

#[derive(serde::Serialize, specta::Type)]
#[serde(tag = "kind", content = "message", rename_all = "camelCase")]
#[specta(remote = Error)]
enum ErrorKind {
    Io(String),
    Utf8(String),
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants