As part of the course βGolang Developer. Professional β prepared a translation of a useful article.
We invite prospective students and everyone interested to participate in the open webinar on the topic "Go-channels outside and inside". During the lesson, participants will receive a simple abstraction in pictures to understand the principles of the channels, learn about the structure of channels at the language level.
Today we will learn how to integrate a Slack application as a serverless backend.
β FaaS ( ) . , , , ! serverless , , HTTP-. , Slack serverless () Go Azure Functions. Slack , , , Slack.
Giphy Slack. Giphy Slack . -, , () , Giphy Random API. Azure Functions Slack.
:
, ;
, Azure Functions Slack;
, , Slack !
- Go ( GitHub). , Azure Functions , Go , . (Custom Handlers) !
?
, - -, . , /, HTTP! , HTTP- - / (input/output bindings) .
, ( )
( HTTP, , . .) (Functions host). , : (payload) - () , , . , .
, (, , ) .
, .
.
βββ cmd
β βββ main.go
βββ funcy
β βββ function.json
βββ go.mod
βββ host.json
βββ pkg
βββ function
βββ function.go
βββ giphy.go
βββ slack.go
{
"bindings": [
{
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
host.json
, , -, HTTP.customHandler.description.defaultExecutablePath
, ,go_funcy
β , -."enableForwardingHttpRequest": true
, HTTP - :
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
},
"customHandler": {
"description": {
"defaultExecutablePath": "go_funcy"
},
"enableForwardingHttpRequest": true
},
"logging": {
"logLevel": {
"default": "Trace"
}
}
}
cmd
pkg
Go. .
cmd/main.go
HTTP-. , /api/funcy β , HTTP- .
func main() {
port, exists := os.LookupEnv("FUNCTIONS_CUSTOMHANDLER_PORT")
if !exists {
port = "8080"
}
http.HandleFunc("/api/funcy", function.Funcy)
log.Fatal(http.ListenAndServe(":"+port, nil))
}
function/function.go
.
β ( Slack) , Slack.
signingSecret := os.Getenv("SLACK_SIGNING_SECRET")
apiKey := os.Getenv("GIPHY_API_KEY")
if signingSecret == "" || apiKey == "" {
http.Error(w, "Failed to process request. Please contact the admin", http.StatusUnauthorized)
return
}
slackTimestamp := r.Header.Get("X-Slack-Request-Timestamp")
b, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to process request", http.StatusBadRequest)
return
}
slackSigningBaseString := "v0:" + slackTimestamp + ":" + string(b)
slackSignature := r.Header.Get("X-Slack-Signature")
if !matchSignature(slackSignature, signingSecret, slackSigningBaseString) {
http.Error(w, "Function was not invoked by Slack", http.StatusForbidden)
return
}
, , Slack, β , (Slack).
vals, err := parse(b)
if err != nil {
http.Error(w, "Failed to process request", http.StatusBadRequest)
return
}
giphyTag := vals.Get("text")
GIF- , GIPHY REST API
giphyResp, err := http.Get("http://api.giphy.com/v1/gifs/random?tag=" + giphyTag + "&api_key=" + apiKey)
if err != nil {
http.Error(w, "Failed to process request", http.StatusFailedDependency)
return
}
resp, err := ioutil.ReadAll(giphyResp.Body)
if err != nil {
http.Error(w, "Failed to process request", http.StatusInternalServerError)
return
}
, GIPHY API, , Slack . !
var gr GiphyResponse
json.Unmarshal(resp, &gr)
title := gr.Data.Title
url := gr.Data.Images.Downsized.URL
slackResponse := SlackResponse{Text: slackResponseStaticText, Attachments: []Attachment{{Text: title, ImageURL: url}}}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(slackResponse)
fmt.Println("Sent response to Slack")
matchSignature
, , slack.go
giphy.go
( function
), , Go (JSON), . , .
! . ! , , .
Go, .
Azure functions Core Tools β ( ).
Slack, .
- API GIPHY, .
, Azure Function Slack - (Slash command).
Azure Functions
-
- (Function App) Azure (Add).
: (Custom Handler) (Runtime stack).
(Hosting ) Linux Consumption (Serverless) (Operating system) (Plan type) .
Application Insights ( ).
(Create), .
- :
App Service plan ( Consumption/Serverless)
GitHub (build
)
git clone https://github.com/abhirockzz/serverless-go-slack-app
cd serverless-go-slack-app
GOOS=linux go build -o go_funcy cmd/main.go
GOOS=linux
Linux, Linux -.
Azure Functions core tools CLI
func azure functionapp publish <enter name of the function app>
URL- , β .
Slack
, Slack (-) :
Slack
-
Slack -
(Create New Command), - . , URL- (Request URL) - , HTTP , , URL-, . , (Save), .
, -, , (Basic Information) , (Install your app to your workspace) (Install App to Workspace) β Slack, , API Slack. , (App Credentials).
- (Signing Secret) ,
β¦ , - SLACKSIGNINGSECRET GIPHYAPIKEY β .
fun(cy) time!
Slack /funcy <search term>
. , /funcy dog
. !
, : /funcy
Slack, , Giphy API , , GIF ( !).
timeout error
Slack . , cold start
, , . , Slack 3 β .
. , , , !
: , , , , , (-, App Service Plan . .).
Go Azure! , . .
Β«Golang Developer. ProfessionalΒ».