Need help with actix-web. It's a pretty simple problem, asked everywhere, but I cannot figure it out anyway

#1

So this is really a simple issue, but I think I need someone to practically point it out for me because I can’t understand how to do what I want to do. I’ve asked a lot of forums and about it and they’ve all told me the same, thing, but I just don’t get it. Anyway here’s what I’ve been doing. I’m creating a slack bot as an exercise to learn more about actix-web and actix. This bot is supposed to monitor github repositories with github’s webhook API and then post messages to slack channels when there is an even that has occurred like a push to a remote branch or a pull request.

Anyway I have been following this tutorial:

It’s very thorough and clear on how to set up a rust REST API. My issue comes from the following block of code, which I just cannot figure out:

// invitation_routes.rs

use actix_web::{AsyncResponder, FutureResponse, HttpResponse, Json, ResponseError, State};
use futures::future::Future;

use app::AppState;
use invitation_handler::CreateInvitation;

pub fn register_email((signup_invitation, state): (Json<CreateInvitation>, State<AppState>))
    -> FutureResponse<HttpResponse> {
    state
        .db
        .send(signup_invitation.into_inner())
        .from_err()
        .and_then(|db_response| match db_response {
            Ok(invitation) => Ok(HttpResponse::Ok().json(invitation)),
            Err(err) => Ok(err.error_response()),
        }).responder()
}

The difference with that code is that I don’t need a State, my slackbot has no state to modify for the moment. I’ve been told to just use an empty state, I get that but I’m not sure what to do, especially with a Future. If someone could help me out and rewrite that code with an example that uses no state but still uses Futures and Json. I’m just completely lost on how to do it and searching out there for something similar has proven ineffective.

#2

The sample code you provided is using a database connector on the State object. It may seem like you don’t need state, but your bot probably does have state in the form of a connection to the slack API. In the actor pattern, you would usually implement this as passing a message to your “Slack integration actor”. This is what the sample code does, using the AppState struct to hold an address to the actor that manages connections to the database.

Does that explanation help?

As you are probably aware, using global state in Rust is kind of a pain (on purpose). Otherwise the naïve approach is just to make your slack API actor globally accessible. Actix instead gives you tools to pass this state around: https://actix.rs/docs/application/#state

And the Databases Pattern in the docs also show that state is what you want for this: https://actix.rs/docs/databases/ The only state contained in this example is the address of an actor that manages a SQLite interface. But this is the pattern you should be following.

#3

Yes, I understand, I had not considered the connection to slack to function like a state. I intended to have the messages being written by another actor however, not the same one that is responsible for monitoring github, otherwise this would be like a one actor application, which is kind of pointless.

#4

You’re still going to need some state, at minimum the Addr for the Actor you’re sending the next message to.

1 Like
#5

Yeah, that was the message I tried to convey. @Elang89 you definitely won’t end up with a single-actor application. Especially as you begin to add features, you will probably want to implement them with clean separation of concerns. The state is essential for message passing between actors.