In this example, we’ll walk through creating a Slack Slash Command service. The source for this is the SpartaSlackbot repo.
Our initial command handler won’t be very sophisticated, but will show the steps necessary to provision and configure a Sparta AWS Gateway-enabled Lambda function.
This lambda handler is a bit more complicated than the other examples, primarily because of the Slack Integration requirements. The full source is:
import (
spartaAWSEvents "github.com/mweagle/Sparta/v3/aws/events"
)
////////////////////////////////////////////////////////////////////////////////
// Hello world event handler
//
func helloSlackbot(ctx context.Context,
apiRequest spartaAWSEvents.APIGatewayRequest) (map[string]interface{}, error) {
logger, _ := ctx.Value(sparta.ContextKeyLogger).(*zerolog.Logger)
bodyParams, bodyParamsOk := apiRequest.Body.(map[string]interface{})
if !bodyParamsOk {
return nil, fmt.Errorf("Failed to type convert body. Type: %T", apiRequest.Body)
}
logger.Info().
Str("BodyType", fmt.Sprintf("%T", bodyParams)).
Str("BodyValue", fmt.Sprintf("%+v", bodyParams)).
Msg("Slack slashcommand values")
// 2. Create the response
// Slack formatting:
// https://api.slack.com/docs/formatting
responseText := "Here's what I understood"
for eachKey, eachParam := range bodyParams {
responseText += fmt.Sprintf("\n*%s*: %+v", eachKey, eachParam)
}
// 4. Setup the response object:
// https://api.slack.com/slash-commands, "Responding to a command"
responseData := map[string]interface{}{
"response_type": "in_channel",
"text": responseText,
"mrkdwn": true,
}
return responseData, nil
}
There are a couple of things to note in this code:
POST
request is application/x-www-form-urlencoded
data. This
data is unmarshalled into the same spartaAWSEvent.APIGatewayRequest using
a customized mapping template.Response Formatting
The lambda function extracts all Slack parameters and if defined, sends the text
back with a bit of Slack Message Formatting:
```go
responseText := "Here's what I understood"
for eachKey, eachParam := range bodyParams {
responseText += fmt.Sprintf("\n*%s*: %+v", eachKey, eachParam)
}
```
Custom Response
The Slack API expects a JSON formatted response, which is created in step 4:
```go
responseData := sparta.ArbitraryJSONObject{
"response_type": "in_channel",
"text": responseText,
}
```
With our lambda function defined, we need to setup an API Gateway so that it’s publicly available:
apiStage := sparta.NewStage("v1")
apiGateway := sparta.NewAPIGateway("SpartaSlackbot", apiStage)
The apiStage
value implies that we want to deploy this API Gateway Rest API as part of Sparta’s provision
step.
Next we create an sparta.LambdaAWSInfo
struct that references the s3ItemInfo
function:
func spartaLambdaFunctions(api *sparta.API) []*sparta.LambdaAWSInfo {
var lambdaFunctions []*sparta.LambdaAWSInfo
lambdaFn, _ := sparta.NewAWSLambda(sparta.LambdaName(helloSlackbot),
helloSlackbot,
iamDynamicRole)
if nil != api {
apiGatewayResource, _ := api.NewResource("/slack", lambdaFn)
_, err := apiGatewayResource.NewMethod("POST", http.StatusCreated)
if nil != err {
panic("Failed to create /hello resource")
}
}
return append(lambdaFunctions, lambdaFn)
}
A few items to note here:
sparta.IAMRoleDefinition{}
definition because our go lambda function doesn’t access any additional AWS services.POST
onlyWith everything configured, we then configure our main()
function to forward to Sparta:
func main() {
// Register the function with the API Gateway
apiStage := sparta.NewStage("v1")
apiGateway := sparta.NewAPIGateway("SpartaSlackbot", apiStage)
// Deploy it
sparta.Main("SpartaSlackbot",
fmt.Sprintf("Sparta app that responds to Slack commands"),
spartaLambdaFunctions(apiGateway),
apiGateway,
nil)
}
and provision the service:
S3_BUCKET=<MY_S3_BUCKETNAME> go run slack.go --level info provision
Look for the Stack output section of the log, you’ll need the APIGatewayURL value to configure Slack in the next step.
INFO[0083] Stack output Description=API Gateway URL Key=APIGatewayURL Value=https://75mtsly44i.execute-api.us-west-2.amazonaws.com/v1
INFO[0083] Stack output Description=Sparta Home Key=SpartaHome Value=https://github.com/mweagle/Sparta
INFO[0083] Stack output Description=Sparta Version Key=SpartaVersion Value=0.1.3
At this point our lambda function is deployed and is available through the API Gateway (https://75mtsly44i.execute-api.us-west-2.amazonaws.com/v1/slack in the current example).
The next step is to configure Slack with this custom integration:
Visit https://slack.com/apps/build and choose the “Custom Integration” option:
On the next page, choose “Slash Commands”:
The next screen is where you input the command that will trigger your lambda function. Enter /sparta
Finally, scroll down the next page to the Integration Settings section and provide the API Gateway URL of your lambda function.
POST
), to match how we configured the API Gateway entry above.Save it
There are additional Slash Command Integration options, but for this example the URL option is sufficient to trigger our command.
With everything configured, visit your team’s Slack room and verify the integration via /sparta
slash command:
Before moving on, remember to decommission the service via:
go run slack.go delete
This example provides a good overview of Sparta & Slack integration, including how to handle external requests that are not application/json
formatted.