-
Notifications
You must be signed in to change notification settings - Fork 44
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
Add Actix #156
Add Actix #156
Conversation
this is done in part by making things more generic
but you can't really tell because cookies don't exist yet
I'm going to invite commentary on these changes, now, even though I'm not quite finished getting it all sorted out. |
Note to self: Don't implement This allows us to share error-response-generating code between Rocket and Actix, and also means all our response errors should maintain consistent formatting. |
We shouldn't be responding with JSON, oops
Getting real close to feature parity, now |
Note to self: Implement a way to figure out which template to use based on the route that was hit (i.e. Implement FromRequest for some TemplateName type). This will make it much cleaner to handle errors in request guards. Maybe this can exist in the following form: pub enum RenderOrRedirect {
Render(TemplateName),
Redirect(RouteName),
}
// Maybe do something a little more magical here, like looking for the '/auth/sign_in' template if the path is '/auth/sign_in'
impl From<&str> for RenderOrRedirect {
fn from(path: &str) -> Self {
"/auth/sign_in" => RenderOrRedirect::Render("sign_in".to_owned()),
...,
_ => "404",
}
}
impl FromRequest<AppConfig> for RenderOrRedirect {
type Config = ();
type Result = Self;
fn from_request(req: &HttpRequest, _: &Self::Config) -> Self::Result {
RenderOrRedirect::from(req.path())
}
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Staaaaaaaaaaaaaaaaaaaaaaaaare
( ⚆ _ ⚆ )
(Jokingly replying to "Don't pay attention.)
(( Will wait for PR to review properly :3c ))
Maybe instead of |
I also don't like the current I do think that the Maybe |
I'm also thinking about implementing a macro called let res = perform!(state, [
FirstAction::new(input_data),
SecondAction::new(other_required_data),
ThirdAction::new(more_required_data),
]); where each action implements |
ultimately, the async our_route(...) -> Result<item, err> {
let first = await!(perform_db_action(FirstAction::new(input_data)))?;
let second = await!(perform_db_action(SecondAction::new(other_required_data).with(first)))?;
Ok(await!(perform_db_action(ThirdAction::new(more_required_data).with(second)?)
} which, to be fair, is still a bit ugly, but we could work out a cleaner look for that when the time comes |
I need to get going, but I'll fix this tomorrow I have a macro and I'm excited by it
I do like the idea of having more... specific errors ( |
The perform macro is completeHere's the sync version for aardwolf-rocket(aardwolf-actix has an async version) macro_rules! perform {
( $state:expr, $start:expr, $error_type:ty, [] ) => {{
// If there's no operations, return the initial value as the result
Ok($start) as Result<_, $error_type>
}};
(
$state:expr,
$start:expr,
$error_type:ty,
[
($wrapper:ty => $first:expr),
$(($wrappers:ty => $rest:expr),)*
]
) => {{
use $crate::action::Action;
// Pass the initial value to the first operation
// and wrap it inside a DbActionWrapper of ValidateWrapper
let wrapper: $wrapper = $first.with($start).into();
// Perform the action, passing the provided state as an argument
let res = wrapper.action($state.clone());
// Call the perform_inner macro with the result of the first operation
// and a list of the remaining operations
perform_inner!($state, $error_type, res, [ $(($wrappers => $rest),)* ])
}};
}
macro_rules! perform_inner {
(
$state:expr,
$error_type:ty,
$first:expr,
[]
) => {{
// If there are no remaining operations, coerce the error
// from the provided result into the $error_type
$first.map_err(|e| {
let e: $error_type = e.into();
e
})
}};
(
$state:expr,
$error_type:ty,
$first:expr,
[
($wrapper:ty => $item:expr),
$(($wrappers:ty => $items:expr),)*
]
) => {{
use $crate::action::Action;
// Coerce the error from the provided result into the
// $error_type
$first
.map_err(|e| {
let e: $error_type = e.into();
e
})
.and_then(|item| {
// Pass the result of the previous operation to the next operation and
// wrap it inside a DbActionWrapper or ValidateWrapper
let wrapper: $wrapper = $item.with(item).into();
// Perform the action
let res = wrapper.action($state.clone());
// call the perform_inner macro with the result of the action, and the
// list of remaining operations
perform_inner!($state, $error_type, res, [ $(($wrappers => $items),)* ])
})
}};
} This macro takes 4 arguments:
Why pass the state?
Action traitThe pub trait Action<T, E>
where
E: Fail,
{
fn action(self, db: &PgConnection) -> Result<T, E>;
} An action is simply a type that has an Example Usage let res = perform!(
state,
id.into_inner(),
PersonaDeleteError,
[
(DbActionWrapper<_, _, _> => FetchPersona),
(DbActionWrapper<_, _, _> => CheckDeletePersonaPermission::new(user.0)),
(DbActionWrapper<_, _, _> => DeletePersona),
]
); This code does the following:
If any of these steps produced an error, it was coerced into the |
diesel warnings are now silenced due to an issue with how nightly builds work: diesel-rs/diesel#1785 |
8efbdc3
to
ffbdc56
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I approve.
This is one heck of a large batch of work. Much appreciated friend! :D
It's ready It's ready It's ready It's ready take a look