1# How to create opaque error types for public APIs 2 3While creating error types on top of Rust enums allows for great 4flexibility inside your code, that same flexibility may not be 5desired in a public API. Public enums also expose their variants 6and the variant's fields, allowing consumers to rely on those 7details. 8 9The most conservative approach is to create an *opaque* error type 10that only implements a handful of traits. This can be done by 11deriving `Snafu` for a newtype struct that contains another SNAFU 12error: 13 14```rust 15# use snafu::Snafu; 16#[derive(Debug, Snafu)] 17pub struct Error(InnerError); 18 19// That's all it takes! The rest is demonstration of how to use it. 20 21pub fn login(id: i32) -> Result<(), Error> { 22 validate_user(id)?; 23 is_user_locked(id)?; 24 Ok(()) 25} 26 27#[derive(Debug, Snafu)] 28enum InnerError { 29 #[snafu(display("User ID {} is invalid", user_id))] 30 InvalidUser { user_id: i32 }, 31 #[snafu(display("User ID {} is locked", user_id))] 32 UserLocked { user_id: i32 }, 33} 34 35fn validate_user(user_id: i32) -> Result<(), InnerError> { 36 InvalidUser { user_id }.fail() 37} 38 39fn is_user_locked(user_id: i32) -> Result<(), InnerError> { 40 UserLocked { user_id }.fail() 41} 42``` 43 44## Delegated traits 45 46- [`Error`][] 47- [`Display`][] 48- [`ErrorCompat`][] 49 50[`Error`]: std::error::Error 51[`Display`]: std::fmt::Display 52[`ErrorCompat`]: crate::ErrorCompat 53 54## `From` 55 56The `From` trait is also implemented to convert the inner type into 57the opaque type. This makes converting from internal errors to public 58errors very easy. 59