github.com/mweagle/Sparta@v1.15.0/docs_source/content/reference/apigateway/slack.md (about) 1 --- 2 date: 2016-03-09T19:56:50+01:00 3 title: Slack SlashCommand 4 weight: 21 5 --- 6 7  8 9 In this example, we'll walk through creating a [Slack Slash Command](https://api.slack.com/slash-commands) service. The source for 10 this is the [SpartaSlackbot](https://github.com/mweagle/SpartaSlackbot) repo. 11 12 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. 13 14 # Define the Lambda Function 15 16 This lambda handler is a bit more complicated than the other examples, primarily because of the [Slack Integration](https://api.slack.com/slash-commands) requirements. The full source is: 17 18 ```go 19 import ( 20 spartaAWSEvents "github.com/mweagle/Sparta/aws/events" 21 ) 22 //////////////////////////////////////////////////////////////////////////////// 23 // Hello world event handler 24 // 25 func helloSlackbot(ctx context.Context, 26 apiRequest spartaAWSEvents.APIGatewayRequest) (map[string]interface{}, error) { 27 logger, _ := ctx.Value(sparta.ContextKeyLogger).(*logrus.Logger) 28 29 bodyParams, bodyParamsOk := apiRequest.Body.(map[string]interface{}) 30 if !bodyParamsOk { 31 return nil, fmt.Errorf("Failed to type convert body. Type: %T", apiRequest.Body) 32 } 33 34 logger.WithFields(logrus.Fields{ 35 "BodyType": fmt.Sprintf("%T", bodyParams), 36 "BodyValue": fmt.Sprintf("%+v", bodyParams), 37 }).Info("Slack slashcommand values") 38 39 // 2. Create the response 40 // Slack formatting: 41 // https://api.slack.com/docs/formatting 42 responseText := "Here's what I understood" 43 for eachKey, eachParam := range bodyParams { 44 responseText += fmt.Sprintf("\n*%s*: %+v", eachKey, eachParam) 45 } 46 47 // 4. Setup the response object: 48 // https://api.slack.com/slash-commands, "Responding to a command" 49 responseData := map[string]interface{}{ 50 "response_type": "in_channel", 51 "text": responseText, 52 "mrkdwn": true, 53 } 54 return responseData, nil 55 } 56 ``` 57 58 There are a couple of things to note in this code: 59 60 1. **Custom Event Type** 61 - The inbound Slack `POST` request is `application/x-www-form-urlencoded` data. This 62 data is unmarshalled into the same _spartaAWSEvent.APIGatewayRequest_ using 63 a customized [mapping template](https://github.com/mweagle/Sparta/blob/master/resources/provision/apigateway/inputmapping_formencoded.vtl). 64 65 1. **Response Formatting** 66 The lambda function extracts all Slack parameters and if defined, sends the `text` back with a bit of [Slack Message Formatting](https://api.slack.com/docs/formatting): 67 68 ```go 69 responseText := "Here's what I understood" 70 for eachKey, eachParam := range bodyParams { 71 responseText += fmt.Sprintf("\n*%s*: %+v", eachKey, eachParam) 72 } 73 ``` 74 75 1. **Custom Response** 76 - The Slack API expects a [JSON formatted response](https://api.slack.com/slash-commands), which is created in step 4: 77 78 ```go 79 responseData := sparta.ArbitraryJSONObject{ 80 "response_type": "in_channel", 81 "text": responseText, 82 } 83 ``` 84 85 # Create the API Gateway 86 87 With our lambda function defined, we need to setup an API Gateway so that it's publicly available: 88 89 ```go 90 apiStage := sparta.NewStage("v1") 91 apiGateway := sparta.NewAPIGateway("SpartaSlackbot", apiStage) 92 ``` 93 94 The `apiStage` value implies that we want to deploy this API Gateway Rest API as part of Sparta's `provision` step. 95 96 # Create Lambda Binding & Resource 97 98 Next we create an `sparta.LambdaAWSInfo` struct that references the `s3ItemInfo` function: 99 100 ```go 101 func spartaLambdaFunctions(api *sparta.API) []*sparta.LambdaAWSInfo { 102 var lambdaFunctions []*sparta.LambdaAWSInfo 103 lambdaFn, _ := sparta.NewAWSLambda(sparta.LambdaName(helloSlackbot), 104 helloSlackbot, 105 iamDynamicRole) 106 107 if nil != api { 108 apiGatewayResource, _ := api.NewResource("/slack", lambdaFn) 109 _, err := apiGatewayResource.NewMethod("POST", http.StatusCreated) 110 if nil != err { 111 panic("Failed to create /hello resource") 112 } 113 } 114 return append(lambdaFunctions, lambdaFn) 115 } 116 ``` 117 118 A few items to note here: 119 120 * We're using an empty `sparta.IAMRoleDefinition{}` definition because our go lambda function doesn't access any additional AWS services. 121 * Our lambda function will be accessible at the _/slack_ child path of the deployed API Gateway instance 122 * Slack supports both [GET and POST](https://api.slack.com/slash-commands) integration types, but we're limiting our lambda function to `POST` only 123 124 # Provision 125 126 With everything configured, we then configure our `main()` function to forward to Sparta: 127 128 ```go 129 func main() { 130 // Register the function with the API Gateway 131 apiStage := sparta.NewStage("v1") 132 apiGateway := sparta.NewAPIGateway("SpartaSlackbot", apiStage) 133 134 // Deploy it 135 sparta.Main("SpartaSlackbot", 136 fmt.Sprintf("Sparta app that responds to Slack commands"), 137 spartaLambdaFunctions(apiGateway), 138 apiGateway, 139 nil) 140 } 141 142 ``` 143 144 and provision the service: 145 146 ```nohighlight 147 S3_BUCKET=<MY_S3_BUCKETNAME> go run slack.go --level info provision 148 ``` 149 150 Look for the _Stack output_ section of the log, you'll need the **APIGatewayURL** value to configure Slack in the next step. 151 152 ```nohighlight 153 INFO[0083] Stack output Description=API Gateway URL Key=APIGatewayURL Value=https://75mtsly44i.execute-api.us-west-2.amazonaws.com/v1 154 INFO[0083] Stack output Description=Sparta Home Key=SpartaHome Value=https://github.com/mweagle/Sparta 155 INFO[0083] Stack output Description=Sparta Version Key=SpartaVersion Value=0.1.3 156 ``` 157 158 159 # Configure Slack 160 161 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). 162 163 The next step is to configure Slack with this custom integration: 164 165 1. Visit https://slack.com/apps/build and choose the "Custom Integration" option: 166 167  168 169 1. On the next page, choose "Slash Commands": 170 171  172 173 1. The next screen is where you input the command that will trigger your lambda function. Enter `/sparta` 174 175  176 177 - and click the "Add Slash Command Integration" button. 178 179 1. Finally, scroll down the next page to the **Integration Settings** section and provide the API Gateway URL of your lambda function. 180 181  182 183 * Leave the _Method_ field unchanged (it should be `POST`), to match how we configured the API Gateway entry above. 184 185 1. Save it 186 187  188 189 190 There are additional Slash Command Integration options, but for this example the **URL** option is sufficient to trigger our command. 191 192 # Test 193 194 With everything configured, visit your team's Slack room and verify the integration via `/sparta` slash command: 195 196  197 198 # Cleaning Up 199 200 Before moving on, remember to decommission the service via: 201 202 ```nohighlight 203 go run slack.go delete 204 ``` 205 206 # Wrapping Up 207 208 This example provides a good overview of Sparta & Slack integration, including how to handle external requests that are not `application/json` formatted.