slack-web icon indicating copy to clipboard operation
slack-web copied to clipboard

Fix interactive payload parsing

Open MaxGabriel opened this issue 8 months ago • 1 comments

I was parsing interactive commands from Slack sent via websocket and realized the parsing of SlackInteractivePayload wasn't working. The JSON it was expecting was actually all under a "payload" key. This seems to match the docs:

The payload will be sent to your configured Request URL in an HTTP POST. The body of that request will contain a payload parameter. Your app should parse this payload parameter as JSON.

https://api.slack.com/messaging/interactivity#understanding_payloads

Here's an example of the JSON I received:

{
  "envelope_id": "4c5b7ddd-93e4-4100-bd31-469dc0da2a74",
  "payload": {
    "type": "block_actions",
    "user": {
      "id": "U6TF7D36Y",
      "username": "max",
      "name": "max",
      "team_id": "T6TBZABPW"
    },
    "api_app_id": "A02JS09R199",
    "token": "at9L8bAfkSgMXMcCXYnEx7W4",
    "container": {
      "type": "message",
      "message_ts": "1744643896.565239",
      "channel_id": "D03HC9XKZBK",
      "is_ephemeral": false
    },
    "trigger_id": "8762673254145.231407351812.1081a4547c3eef355373a7b1c4d3cc55",
    "team": {
      "id": "T6TBZABPW",
      "domain": "mercurytechnologies",
      "enterprise_id": "E088T4586SY",
      "enterprise_name": "Mercury"
    },
    "enterprise": {
      "id": "E088T4586SY",
      "name": "Mercury"
    },
    "is_enterprise_install": false,
    "channel": {
      "id": "D03HC9XKZBK",
      "name": "directmessage"
    },
    "message": {
      "user": "U02JBAN4TMM",
      "type": "message",
      "ts": "1744643896.565239",
      "bot_id": "B02JS1B80JW",
      "app_id": "A02JS09R199",
      "text": "Mark Read button",
      "team": "T6TBZABPW",
      "blocks": [
        {
          "type": "actions",
          "block_id": "Da20m",
          "elements": [
            {
              "type": "button",
              "action_id": "button1",
              "text": {
                "type": "plain_text",
                "text": "Mark Read",
                "emoji": true
              }
            }
          ]
        }
      ]
    },
    "state": {
      "values": {}
    },
    "response_url": "https://hooks.slack.com/actions/T6TBZABPW/8762673200785/jUHi85fRbVeX5XHtgG6qyVP4",
    "actions": [
      {
        "action_id": "button1",
        "block_id": "Da20m",
        "text": {
          "type": "plain_text",
          "text": "Mark Read",
          "emoji": true
        },
        "type": "button",
        "action_ts": "1744643994.442584"
      }
    ]
  },
  "type": "interactive",
  "accepts_response_payload": false
}

I have not actually built slack-web and confirmed this works, but I did modify my own code like so:

newtype InteractiveRequest = InteractiveRequest 
  { payload :: SlackInteractivePayload 
  } deriving stock (Show)

instance FromJSON InteractiveRequest where
  parseJSON = withObject "InteractiveRequest" $ \o -> do
    payload <- o .: "payload"
    pure $ InteractiveRequest payload

and that seems to have worked correctly

Before submitting your PR, check that you've:

n/a

n/a

After submitting your PR:

  • [x] Update the Changelog.md file with a link to your PR
  • [x] Bumped the version number if there isn't an (unreleased) on the Changelog
  • [ ] Check that CI passes (or if it fails, for reasons unrelated to your change, like CI timeouts)

MaxGabriel avatar Apr 15 '25 12:04 MaxGabriel

Actually wait a minute.... Are we sure this isn't a SlackWebhookEvent? https://github.com/MercuryTechnologies/slack-web/blob/a802937ce60cc079b5df756030d671b7af7fec26/src/Web/Slack/Experimental/Events/Types.hs#L388-L394

The thing that's weird here is that those docs could also be read as "it's x-form-urlencoded with a payload parameter containing JSON". And the second weirdness is that this is using websocket mode, so it could be an artifact of websocket mode.

I am a little bit confused as to what context you got that data in.

lf- avatar Apr 15 '25 18:04 lf-