Package: slackers
SlackersSlack webhooks API served by FastAPIWhat is SlackersSlackers is aFastAPIimplementation to handle Slack interactions and events.
It serves endpoints to receiveslash commands,app actions,interactive components.
It also listens for events sent to the Slack Events APISlack Events.InstallationYou can install Slackers with pip$ pip install slackersConfigurationSLACK_SIGNING_SECRETYou must configure the slack signing secret. This will be used to
verify the incoming requests signature.$ export SLACK_SIGNING_SECRET=your_slack_signing_secretExample usageSlackers will listen for activity from the Events API on/events, for
interactive components on/actionsand for slash commands on/commands.
When an interaction is received, it will emit an event. You can listen
for these events as shown in the following examples.On receiving a request, Slackers will emit an event which you can handle yourself.
Slackers will also respond to Slack with an (empty) http 200 response telling Slack
all is well received.Starting the serverAs said, Slackers uses the excellent FastAPI to serve it's endpoints. Since you're here,
I'm assuming you know what FastAPI is, but if you don't, you can learn all about
how that works withthis tutorial.Slackers offers you a router which you can include in your own FastAPI.fromfastapiimportFastAPIfromslackers.serverimportrouterapp=FastAPI()app.include_router(router)# Optionally you can use a prefixapp.include_router(router,prefix='/slack')EventsOnce your server is running, the events endpoint is setup at/events, or if you use
the prefix as shown above, on/slack/events.Accepting the challengeWhen setting up Slack tosend events,
it will first send a challenge to verify your endpoint. Slackers detects when a challenge is sent.
You can simply start our api and Slackers will meet the challenge automatically.Responding to eventsOn receiving an event, Slackers will emit a python event, which you can act upon as shown below.importloggingfromslackers.hooksimporteventslog=logging.getLogger(__name__)@events.on("app_mention")defhandle_mention(payload):log.info("App was mentioned.")log.debug(payload)ActionsOnce your server is running, the actions endpoint is setup at/actions, or if you use
the prefix as shown above, on/slack/actions.Responding to actionsOn receiving an action, Slackers will emit a python event, which you can listen for as
shown below. You can listen for the action type, or more specifically for the action id
or callback id linked to the action.importloggingfromslackers.hooksimportactionslog=logging.getLogger(__name__)# Listening for the action type.@actions.on("block_actions")defhandle_action(payload):log.info("Action started.")log.debug(payload)# Listen for an action by it's action_id@actions.on("block_actions:your_action_id")defhandle_action_by_id(payload):log.info("Action started.")log.debug(payload)# Listen for an action by it's callback_id@actions.on("block_actions:your_callback_id")defhandle_action_by_callback_id(payload):log.info(f"Action started.")log.debug(payload)Interactive messagesInteractive message actions do not have anaction_id. They do have anameand atype.
To act upon interactive messages, you can listen for the action type,interactive_messageas wel as the combination of theinteractive_messageandname,typeor both.importloggingfromslackers.hooksimportactionslog=logging.getLogger(__name__)# Listening for the action type.@actions.on("interactive_message")defhandle_action(payload):log.info("Action started.")log.debug(payload)# Listen for an action by it's name@actions.on("interactive_message:action_name")defhandle_action_by_id(payload):log.info("Action started.")log.debug(payload)# Listen for an action by it's type@actions.on("interactive_message:action_type")defhandle_action_by_callback_id(payload):log.info(f"Action started.")log.debug(payload)# Listen for an action by it's name and type@actions.on("interactive_message:action_name:action_type")defhandle_action_by_callback_id(payload):log.info(f"Action started.")log.debug(payload)Custom responsesSlackers tries to be fast to respond to Slack. The events you are listening for with the
likes of@actions.on(...)are scheduled as an async task in a fire and forget fashion.
After scheduling these events, Slackers will by default return an empty 200 response which
might happen before the events are handled.In some cases you might want to act on the payload and return a custom response to Slack.
For this, you can use the slackersresponderdecorator to define your custom handler
function. This function is then used as a callback instead of returning the default response.
You must ensure your custom handler returns astarlette.responses.Responseor one of it's
subclasses. You must furthermore ensure that there is only one responder responding to your
Slack request.Please note that the events are also emitted, so you could have both@actions.on("block_action:xyz")and@responder("block_action:xyz"). Just keep in mind that the event emissions are async and are
not awaited. In other words, Slackers doesn't ensure that the response (whether your custom response
or the default) is returned before or after the events are emitted.fromstarlette.responsesimportJSONResponsefromslackers.hooksimportresponder@responder("block_actions:your_callback_id")defcustom_handler(payload):# handle your payload...returnJSONResponse(content={"custom":"Custom Response"})Slash commandsOnce your server is running, the commands endpoint is setup at/commands, or if you use
the prefix as shown above, on/slack/commands. Slackers will emit an event with the name
of the command, so if your command is/engage, you can listen for the eventengage(without the slash)Responding to slash commandsOn receiving a command, Slackers will emit a python event, which you can listen for as shown below.importloggingfromslackers.hooksimportcommandslog=logging.getLogger(__name__)@commands.on("engage")# responds to "/engage"defhandle_command(payload):log.info("Command received")log.debug(payload)AsyncSince events are emitted using pyee's Async event emitter, it is possible to define your event handlers
as async functions. Just keep in mind that errors are in this case emitted on the 'error' event.importloggingfromslackers.hooksimportcommandslog=logging.getLogger(__name__)@commands.on('error')deflog_error(exc):log.error(str(exc))@commands.on("engage")# responds to "/engage"asyncdefhandle_command(payload):...