Issue
I am developing a simple Slack app with Python and Flask. It should respond to a slash command with a message containing a button. And it respond to the user clicking the button.
The problem is: The response message to the interactive message request is not posted in the Slack channel after clicking the button.
Details
After clicking the button I can see the request coming in on my Python console e.g.
127.0.0.1 - - [24/Jun/2019 17:30:09] "POST /interactive HTTP/1.1" 200 -
And I can see my app responding to this request on my ngrok inspect page:
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 25
Server: Werkzeug/0.14.1 Python/3.7.0
Date: Mon, 24 Jun 2019 15:41:57 GMT
{
"text": "Hi there"
}
But the response message will not be shown on Slack. Also there is no service error shown on Slack, so it seams Slack is getting a 200 OK response.
Also if I send my interactive response to the response_url
it works fine. Just trying to respond directly to the HTTP request does not.
Interestingly I am using the exact same approach to respond to the slash command and the interactive request. It works for the first but not for the latter.
Setup
I am running my app in debug mode on Python development server on port 8000. The server is exposed to Slack using ngrok. ngrok has my external URL mapped to localhost:8000
. The app is started from within Visual Studio Code.
The request URLs are configured correctly to the respective endpoints for both slash command and interactive action.
Code
import requests
from flask import Flask, json
app = Flask(__name__) #create the Flask app
@app.route('/slash', methods=['POST'])
def slash_response():
""" endpoint for receiving all slash command requests from Slack """
# blocks defintion from message builder
# converting from JSON to array
blocks = json.loads("""[
{
"type": "section",
"text": {
"type": "plain_text",
"text": "Please select an option:",
"emoji": true
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Click me",
"emoji": true
},
"value": "button_1"
}
]
}
]""")
# compose response message
response = {
"blocks": blocks
}
## convert response message into JSON and send back to Slack
return json.jsonify(response)
@app.route('/interactive', methods=['POST'])
def interactive_response():
""" endpoint for receiving all interactivity requests from Slack """
# compose response message
response = {
"text": "Hi there"
}
## convert response message into JSON and send back to Slack
return json.jsonify(response)
if __name__ == '__main__':
app.run(debug=True, port=8000) #run app in debug mode on port 8000
Solution
I found a section on the Slack API page that explains what's going on with your interactive component!
Everything I am about to go over is in the Responding to the interaction section of the official documentation.
There are two steps to responding to an interaction:
- Acknowledgment response - send an OK 200 back to slack within 3 seconds of receiving the request payload. The text you send with this response will not alter the contents of the current slack message.
- Composed response - send your updated message to slack using a POST request and the response_url they package in the request payload.
So the reason OP's code does not work is that Slack does no longer accept a full message as direct response to an interaction. Instead all response messages need to be send to the response_url
.
However, to enable backwards compatibility it is still possible to respond directly with message including attachments, but not with messages containing layout blocks.
Code
Here is the code I used to substitute the original button message with the text "Hi Erik!"
import requests
from flask import Flask, json, request
app = Flask(__name__) #create the Flask app
@app.route('/slash', methods=['POST'])
def slash_response():
""" endpoint for receiving all slash command requests from Slack """
# blocks defintion from message builder
# converting from JSON to array
blocks = json.loads("""[
{
"type": "section",
"text": {
"type": "plain_text",
"text": "Please select an option:",
"emoji": true
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Click me",
"emoji": true
},
"value": "button_1"
}
]
}
]""")
# compose response message
response = {
"blocks": blocks
}
## convert response message into JSON and send back to Slack
return json.jsonify(response)
@app.route('/interactive', methods=['POST'])
def interactive_response():
""" endpoint for receiving all interactivity requests from Slack """
# compose response message
data = json.loads(request.form["payload"])
response = {
'text': 'Hi Erik!',
}
requests.post(data['response_url'], json=response)
return ''
if __name__ == '__main__':
app.run(debug=True, port=8000) #run app in debug mode on port 8000
Answered By - CalebSE
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.