Erstellen einer serverlosen Anwendung mit Azure-Funktionen und Los

Im Rahmen des Kurses „Golang Developer. Professional “ erstellte eine Übersetzung eines nützlichen Artikels.



Wir laden Studieninteressierte und alle ein, die am offenen Webinar zum Thema
"Go-Kanäle außen und innen" teilnehmen möchten . In der Lektion erhalten die Teilnehmer eine einfache Abstraktion in Bildern, um die Prinzipien der Kanäle zu verstehen und die Struktur der Kanäle auf Sprachebene kennenzulernen.






Heute lernen wir, wie man eine Slack-Anwendung als serverloses Backend integriert.

— FaaS ( ) . , , , ! serverless , , HTTP-. , Slack serverless () Go Azure Functions. Slack , , , Slack.





Giphy Slack. Giphy Slack . -, , () , Giphy Random API. Azure Functions Slack.





:





  • (Custom Handlers) Azure Functions;





  • , ;





  • , 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
      
      



  • function.json



    , ( )





{
    "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 — GIHPY ( !) . API.





- API GIPHY, .





, Azure Function Slack - (Slash command).





Azure Functions

(Resource Group) .





-

- (Function App) Azure (Add).





: (Custom Handler) (Runtime stack).





(Hosting ) Linux Consumption (Serverless) (Operating system) (Plan type) .





Application Insights ( ).





(Create), .





- :





  • App Service plan ( Consumption/Serverless)





  • Azure Storage





  • Azure Application Insights





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 -

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».





«Go- ».












All Articles