Sending Json in response to Slack

I have a Slack slash command that I would like to implement, but I’m having difficulty responding correctly. No matter what I try, Slack is tacking the json and posting it as is, rather than interpreting its API is supposed to. Other methods of interacting with Slack work normally, so I think it’s something to do with how I’m using UD.

New-UDEndpoint -Url "/commands" -Method "POST" -Endpoint {
param(
    $token,
    $channel_id,
    $channel_name,
    $user_id,
    $user_name,
    $command,
    $text,
    $response_url,
    $trigger_id  
)
#Wait-Debugger
$j = @{
    response_type = "in_channel"
    text = "hello"
}
$j | ConvertTo-Json

In the Slack channel, it just posts
{
“text”: “hello”,
“response_type”: “in_channel”
}

I have noticed if I simply don’t put any output at all, Slack actually posts ‘[]’, which is interesting. I was able to get rid of this with this line:

[Microsoft.AspNetCore.Http.HttpResponseWritingExtensions]::WriteAsync($Response, ‘’)

But this only works with a basic text string. I’ve tried sending JSON that way and the same thing as above happens.

Could you provide an example of your REST call to the SLACK API?

I see $j | ConvertTo-Json is going to return JSON, just would like an example of what you are passing that onto slack to help troubleshoot. Thanks!

It works fine when I do an actual Invoke-RestMethod, but when I attempt to return json in the 200 response, which is what Slack wants you to do, it doesn’t work as I’m expecting it to.

Slack gives you 3 seconds to send a 200 response. After that you can do whatever, so you can just send a blank 200 and then do other stuff and respond later, but if you want to respond right away you can send JSON encoded stuff that follows what their APIs expect. This is what I’m struggling to work out.

Here’s my endpoint:

New-UDEndpoint -Url "/commands" -Method "POST" -Endpoint {
    param(
        $token,
        $channel_id,
        $channel_name,
        $user_id,
        $user_name,
        $command,
        $text,
        $response_url,
        $trigger_id  
    )
    #Wait-Debugger
    
    if ($token -eq $VerificationToken) {
        $SlackResponse = @{
            trigger_id = $trigger_id
        }

        switch ($command) {
            '/rbac' {
                [Microsoft.AspNetCore.Http.HttpResponseWritingExtensions]::WriteAsync($Response, "")
                Show-RbacHome -SlackResponse $SlackResponse
            }
            '/test' {
                "Test" | ConvertTo-Json
            }
        }
    }
}

And the Slack output:
image

If I simply put

"test"

It outputs the text correctly with no quote marks. If I attempt to follow their api format, it fails again.

            '/test' {
            $text = @{
                text          = "hello"
                response_type = "in_channel"
            }
            $text | ConvertTo-Json
        }

It includes just renders the JSON exactly as is.

image

Instead of just saying the word hello in the channel, rather than ephemeral which is the default.

I have confirmed this behaves the same on WIndows and Linux. Also, when I run Get-UDContentType, it returns application/x-www-form-urlencoded, even though I thought UD always sends application/json by default. When I explicitly set the contenttype to json, it does not change the behavior. Slack does both of these contentTypes, but in the past I’ve always used json. This is quite odd behavior.

Get-UDContentType is returning the request’s content type. So Slack is sending in form data. I wonder if it’s expecting form data when it does this.

I can try and futz with this today and see if I can come up with a solution.

Hmmm. You may be right. Slack can take both JSON and form data, but I reread some of their documentation (https://api.slack.com/interactivity/handling) and it may be that in the acknowledgement response it requires form data, not JSON.

In my previous attempts at a Slack/PowerShell app I never used the acknowledgement response to send anything other than the 200.

Although here (https://api.slack.com/interactivity/slash-commands) seems to indicate JSON is accepted…

Sorry for the delay but I figured out the issue and a work around.

TLDR:

    $j = @{
        response_type = "in_channel"
        text = "hello"
    }
    $j | ConvertTo-Json

    $Request.ContentType = 'application/json'

Long Story:

UD isn’t honoring the $Response.ContentType when you set it. What it is attempting to do is return the same content type as the request. If the request hasn’t sent a content-type, it will use “application/json; charset=utf8”. This is a valid content-type but slack is expecting exactly “application/json” without the charset. We can work around the UD issue by setting the request content type during the execution of the endpoint.

And it works!

image

2 Likes