All Products
Search
Document Center

Function Compute:Handlers

Last Updated:Apr 08, 2024

You can use Go handlers to respond to received events and execute the corresponding business logic. This topic describes the concepts and structure of Go handlers and provides examples.

Note

If you want to use HTTP triggers or custom domain names to access functions, obtain request struct before you define HTTP responses. For more information, see Use an HTTP trigger to invoke a function.

What is a handler?

A handler for a function in Function Compute is the method that is used to process requests in function code. When a function is invoked, Function Compute uses the handler that you configure to process requests. You can configure a handler by specifying the Handler parameter in the Function Compute console.

A handler of a Go function in Function Compute is compiled into an executable binary file. You need to only set the handler of your function in Function Compute to the name of the executable file.

For more information about the definitions and operations of functions in Function Compute, see Manage functions.

Configurations of handlers must conform to the configuration specifications of Function Compute. The configuration specifications vary based on the handler type.

Examples

In Go code, you need to introduce the official SDK library aliyun/serverless/fc-runtime-go-sdk/fc and implement the handler and main functions. The following sample code shows an example:

package main

import (
    "fmt"
    "context"

    "github.com/aliyun/fc-runtime-go-sdk/fc"
)

type StructEvent struct {
    Key string `json:"key"`
}

func HandleRequest(ctx context.Context, event StructEvent) (string, error) {
    return fmt.Sprintf("hello, %s!", event.Key), nil
}

func main() {
    fc.Start(HandleRequest)
}

The value of input event is a JSON string that contains the key property. The following sample code provides an example:

{
  "key": "value"
}

Parameter description:

  • package main: the main package. Each Go application contains a main package.

  • import: imports Function Compute dependencies. You need to import the following dependencies:

    • github.com/aliyun/fc-runtime-go-sdk/fc: the core library for Go in Function Compute

    • context: the Go context object in Function Compute.

  • func HandleRequest(ctx context.Context, event StructEvent) (string, error): the handler, which must contain the code to execute. The following items describe the parameters:

    • ctx context.Context: the runtime context information for your Function Compute function. For more information, see Context.

    • event StructEvent: data to be passed in when the function is invoked. Multiple data types are supported.

    • string, error: the return message, which contains a string and an error message. For more information, see Error handling.

    • return fmt.Sprintf("Hi,%s !", event.Key), nil: returns the hello information, which contains the input event. If nil is returned, no error occurs.

  • func main(): the entry point for running the code of the Function Compute function. Go programs must contain main functions. The fc.Start(HandleRequest) code allows your program to run on Alibaba Cloud Function Compute.

Event handler signatures

The following items list valid event handler signatures. Among these signatures, InputType and OutputType are compatible with the encoding/json standard library.

Function Compute deserializes the InputType input by using the json.Unmarshal method and serializes the returned OutputType by using the json.Marshal method. For information about how to deserialize the data that is returned by a function, see JSON Unmarshal.

  • func ()

  • func () error

  • func (InputType) error

  • func () (OutputType, error)

  • func (InputType) (OutputType, error)

  • func (context.Context) error

  • func (context.Context, InputType) error

  • func (context.Context) (OutputType, error)

  • func (context.Context, InputType) (OutputType, error)

You must use a handler based on the following rules:

  • The handler must be a function.

  • The handler can contain up to two input parameters. If the handler contains two input parameters, the first input parameter must be context.Context.

  • The handler can return up to two values. If only one value is returned, the value must indicate the error type. If two values are returned, the second value must indicate the error message.

The following section describes the sample code for handlers:

  • event-struct.go: the sample code for a handler whose event object is of the STRUCT type.

  • event-string.go: the sample code for a handler whose event object is of the STRING type.

  • event-map.go: the sample code for a handler whose event object is of the map[string]interface{} type.

For more information about the sample code for other handlers, see examples.

Context

For more information about how to use context, see Context.

Use an HTTP trigger to call a function

Sample code

package main

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/aliyun/fc-runtime-go-sdk/fc"
)

// HTTPTriggerEvent HTTP Trigger Request Event
type HTTPTriggerEvent struct {
	Version         *string           `json:"version"`
	RawPath         *string           `json:"rawPath"`
	Headers         map[string]string `json:"headers"`
	QueryParameters map[string]string `json:"queryParameters"`
	Body            *string           `json:"body"`
	IsBase64Encoded *bool             `json:"isBase64Encoded"`
	RequestContext  *struct {
		AccountId    string `json:"accountId"`
		DomainName   string `json:"domainName"`
		DomainPrefix string `json:"domainPrefix"`
		RequestId    string `json:"requestId"`
		Time         string `json:"time"`
		TimeEpoch    string `json:"timeEpoch"`
		Http         struct {
			Method    string `json:"method"`
			Path      string `json:"path"`
			Protocol  string `json:"protocol"`
			SourceIp  string `json:"sourceIp"`
			UserAgent string `json:"userAgent"`
		} `json:"http"`
	} `json:"requestContext"`
}

func (h HTTPTriggerEvent) String() string {
	jsonBytes, err := json.MarshalIndent(h, "", "  ")
	if err != nil {
		return ""
	}
	return string(jsonBytes)
}

// HTTPTriggerResponse HTTP Trigger Response struct
type HTTPTriggerResponse struct {
	StatusCode      int               `json:"statusCode"`
	Headers         map[string]string `json:"headers,omitempty"`
	IsBase64Encoded bool              `json:"isBase64Encoded,omitempty"`
	Body            string            `json:"body"`
}

func NewHTTPTriggerResponse(statusCode int) *HTTPTriggerResponse {
	return &HTTPTriggerResponse{StatusCode: statusCode}
}

func (h *HTTPTriggerResponse) String() string {
	jsonBytes, err := json.MarshalIndent(h, "", "  ")
	if err != nil {
		return ""
	}
	return string(jsonBytes)
}

func (h *HTTPTriggerResponse) WithStatusCode(statusCode int) *HTTPTriggerResponse {
	h.StatusCode = statusCode
	return h
}

func (h *HTTPTriggerResponse) WithHeaders(headers map[string]string) *HTTPTriggerResponse {
	h.Headers = headers
	return h
}

func (h *HTTPTriggerResponse) WithIsBase64Encoded(isBase64Encoded bool) *HTTPTriggerResponse {
	h.IsBase64Encoded = isBase64Encoded
	return h
}

func (h *HTTPTriggerResponse) WithBody(body string) *HTTPTriggerResponse {
	h.Body = body
	return h
}

func HandleRequest(event HTTPTriggerEvent) (*HTTPTriggerResponse, error) {
	fmt.Printf("event: %v\n", event)
	if event.Body == nil {
		return NewHTTPTriggerResponse(http.StatusBadRequest).
			WithBody(fmt.Sprintf("the request did not come from an HTTP Trigger, event: %v", event)), nil
	}

	reqBody := *event.Body
	if event.IsBase64Encoded != nil && *event.IsBase64Encoded {
		decodedByte, err := base64.StdEncoding.DecodeString(*event.Body)
		if err != nil {
			return NewHTTPTriggerResponse(http.StatusBadRequest).
				WithBody(fmt.Sprintf("HTTP Trigger body is not base64 encoded, err: %v", err)), nil
		}
		reqBody = string(decodedByte)
	}
	return NewHTTPTriggerResponse(http.StatusOK).WithBody(reqBody), nil
}

func main() {
	fc.Start(HandleRequest)
}

In the preceding example, HTTPTriggerEvent declares the request format of the HTTP trigger, and HTTPTriggerResponse declares the response format of the HTTP trigger. For more information about formats of request payloads and response payloads of HTTP triggers, see Use an HTTP trigger to invoke a function.

Before you start

Use the preceding example to create a function in a Go runtime and create an HTTP trigger. For more information, see Create a function and Create a trigger.

Procedure

  1. Log on to the Function Compute console. In the left-side navigation pane, click Functions.

  2. In the top navigation bar, select a region. On the Functions page, click the function that you want to manage.

  3. On the function details page, click the Configuration tab. In the left-side navigation pane, click Trigger. On the Trigger page, obtain the public endpoint of the HTTP trigger.

  4. Run the following command to invoke the function:

    curl -i "https://http-trigger-demo.cn-shanghai.fcapp.run" -d "Hello FC!"
    Important
    • If the Authentication Method parameter of the HTTP trigger is set to No Authentication, you can use Postman or Curl to invoke the function. For more information, see Procedure.

    • If the Authentication Method parameter of the HTTP trigger is set to Signature Authentication or JWT Authentication, you can use the signature method or JWT authentication method to invoke the function. For more information, see Authentication.

Possible errors

This sample code can be called by using an HTTP trigger or a custom domain name. If you use an API operation but the configured test parameters do not comply with the request format requirements of HTTP triggers, an error is reported.

For example, the following error message is returned if you invoke the function by clicking Test Function in the Function Compute console after you configure the request parameters as "Hello, FC!".

{
    "statusCode": 400,
    "body": "the request did not come from an HTTP Trigger, event: {\n  \"version\": null,\n  \"rawPath\": null,\n  \"headers\": null,\n  \"queryParameters\": null,\n  \"body\": null,\n  \"isBase64Encoded\": null,\n  \"requestContext\": null\n}"
}

If you want to obtain the original request event payload, you can use the handler in the following example.

// GetRawRequestEvent: obtain the raw request event
func GetRawRequestEvent(event []byte) (*HTTPTriggerResponse, error) {
	fmt.Printf("raw event: %s\n", string(event))
	return NewHTTPTriggerResponse(http.StatusOK).WithBody(string(event)), nil
}

func main() {
	fc.Start(GetRawRequestEvent)
}