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