So the answer to both of those things is that I basically hammered out a bit of code that looks sort of like what I have but it's exactly. It should have been a 503 error instead.

In reality, the main thought is that the map_err in the controller should take some error and match against it for a known set of Error enums to translate to an enum that we want to get back out to the user.

> Also, I take it this code returns a body of { status: ..., message: ... } with a status of HTTP 500? So the enum variant "Unavailable" is just for programming syntax and unwraps around the Json<T> inner body when it's called by Rocket?

Yep! Exactly. It's a bit wonky but I thought it would be helpful to show off, especially in a world where JSON bodies with a shape of { status: "error" ... } are so common. In reality you can shove whatever you want in there and use serde to flatten the result. Off the top of my head, you could in theory do something like

pub struct UserApiErrorMessage {
status: String,
message: String,
#[serde(flatten)]
_meta: HashMap<...>
}

Where _meta holds some additional information you might want to dump to the user. In practice, I'm using this error enum approach to construct JSONAPI responses with appropriate status codes and the appropriate structure.

> Finally, I see you are making your diesel calls inside the controller.

So what I've found is that generally you actually don't want to embed your diesel get_result(s) calls inside your impls for your struct, since you're loading the entire set up into memory at once and you lose the ability to cut down. I've leveraged the `into_boxed` method of the query builder pretty heavily to allow for building up queries on the fly, which allows me to abstract the common bits into the impl. Code shows better than words so here we go:

struct User { .. }

type WithUsername<'a> = Eq<users::username, String>;

impl User {
pub fn read_all<'a>() -> BoxedQuery<'a, Pg> {
users::table.order(users::created_at).into_boxed()
}

fn with_username(username: &String) -> WithUsername {
users::username.eq(username)
}
}

// In some method somewhere. Note: I don't know that this actually works out of the box because I didn't compile it
User::read_all().filter(User::with_username(&username)).paginate(1).per_page(25).get_results::<User>()?

So I've cooked up a sort-of ORM for this, but I've abstracted away that underlying schema.rs file that's a huge part of diesel, since I think (but haven't proven) that leaking that file out into the rest of the codebase makes things tougher in the long run.

As to your point about the controller, I'd advise against it but hacked something together for the comment. In my project, I actually call out to simple services (think shitty service oriented architecture) that query the database and return a Result. What's interesting (or not) here is that my services actually call the `Into::into` of the database model, so my controller never even sees that they exist. Again, some code:

// Actually in some other file
mod service {
mod users {
pub fn get_user_page(conn: &PgConnection) -> Result<Vec<UserApiResponse>> {
let users = User:read_all().paginate(1).per_page(25).get_results::<User>()?;
users.iter().map(Into::into).collect::<Vec<_>>()
}
}
}

#[get("/users")]
fn index(connection: &PgConnection) -> Result<Json<Vec<UserApiResponse>>> {
service::users::get_user_page(&*connection).map(Json).map_err(...)
}

But now we come to what I think is the most pertinent question: why does this exist? Testing. Spinning up a DB in CI is quite easy but since rust runs all testing in parallel (yay fearless concurrency!), we can get into trouble when we delete some records from the database but we haven't set up our tests to handle that. I ran into some really stupid problems I caused for myself in assuming that somehow it would be like rspec. If you can basically abstract away the database access part into a dumb hashmap, you get a store per test that won't experience much contention (at least that's the hope). I'm still working on that last bit so my thoughts on it are far and away from complete.

EDIT: Final note on diesel: there is no into_boxed for inserts and into_boxed for updates is dark magic that I can never get working correctly, so I'd avoid being too clever with these and focus on Select/Delete instead