Building a Serverless Application Using Azure Functions and Go

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.





:





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