Function Compute supports API Gateway as the event source. You can specify Function Compute as the backend service of APIs. After the configuration is complete, API Gateway triggers the associated function to be executed once if you set the backend service of the request to Function Compute. Function Compute returns the execution result to API Gateway. This topic describes how to configure an API Gateway trigger, including how to write a function, test a function, and verify results.

Write a function

After you create an API, you can write a function.

  1. Log on to the Function Compute console.
  2. In the left-side navigation pane, click Services and Functions.
  3. In the top navigation bar, select the region where the service resides.
  4. On the Services page, find the service that you want to manage and click Functions in the Actions column.
  5. On the Functions page, click the name of the function that you want to manage.
    hanshuguanli
  6. On the function details page, click the Function Code tab and write code in the code editor.
    The following sample code shows code in different languages:
    • Node.js
      module.exports.handler = function(event, context, callback) { 
         var event = JSON.parse(event);
         var content = {
           path: event.path,
           method: event.method,
           headers: event.headers,
           queryParameters: event.queryParameters,
           pathParameters: event.pathParameters,
           body: event.body
         // You can write your own logic here.   
         }
         var response = {
              isBase64Encoded: false,
              statusCode: '200',
              headers: {
                'x-custom-header': 'header value'
              },
              body: content
            }; 
         callback(null, response)
      };                               
    • Python
      # -*- coding: utf-8 -*-
      import json
      
      def handler(event, context):
          event = json.loads(event)
          content = {
              'path': event['path'],
              'method': event['httpMethod'],
              'headers': event['headers'],
              'queryParameters': event['queryParameters'],
              'pathParameters': event['pathParameters'],
              'body': event['body']
          }
          # You can write your own logic here.  
          rep = {
              "isBase64Encoded": "false",
              "statusCode": "200",
              "headers": {
                  "x-custom-header": "no"
              },
              "body": content
          }
          return json.dumps(rep)                                
    • PHP
      <?php
      function handler($event, $context) {
          $event   = json_decode($event, $assoc = true);
          $content = [
              'path'            => $event['path'],
              'method'          => $event['httpMethod'],
              'headers'         => $event['headers'],
              'queryParameters' => $event['queryParameters'],
              'pathParameters'  => $event['pathParameters'],
              'body'            => $event['body'],
          ];
      
          $rep = [
              "isBase64Encoded" => "false",
              "statusCode"      => "200",
              "headers"         => [
                  "x-custom-header" => "no",
              ],
              "body"            => $content,
          ];
      
          return json_encode($rep);
      }                               
    • Java

      When you program in Java, you must implement a class that uses a predefined handler method for Function Compute. Two predefined handler methods are available. For more information about the Java runtime environment of Function Compute, see Java runtime environments.

      • (Recommended) Use PojoRequestHandler<I, O> handler.
        import com.aliyun.fc.runtime.Context;
        import com.aliyun.fc.runtime.PojoRequestHandler;
        import java.util.HashMap;
        import java.util.Map;
        
        public class ApiTriggerDemo implements PojoRequestHandler<ApiRequest, ApiResponse> {
        
            public ApiResponse handleRequest(ApiRequest request, Context context) {
                // Obtain the API request information. 
                context.getLogger().info(request.toString());
                String path = request.getPath();
                String httpMethod = request.getHttpMethod();
                String body = request.getBody();
                context.getLogger().info("path:" + path);
                context.getLogger().info("httpMethod:" + httpMethod);
                context.getLogger().info("body:" + body);
        
                // You can write your own logic here. 
        
                // API response example. 
                Map headers = new HashMap();
                boolean isBase64Encoded = false;
                int statusCode = 200;
                String returnBody = "";
                return new ApiResponse(headers,isBase64Encoded,statusCode,returnBody);
            }
        }                                        
        • The following sample defines the two POJO classes: ApiRequest and ApiResponse.
          Note The set() and get() methods of the POJO classes must be specified.
          import java.util.Map;
          
          public class ApiRequest {
              private String path;
              private String httpMethod;
              private Map headers;
              private Map queryParameters;
              private Map pathParameters;
              private String body;
              private boolean isBase64Encoded;
          
              @Override
              public String toString() {
                  return "Request{" +
                          "path='" + path + '\'' +
                          ", httpMethod='" + httpMethod + '\'' +
                          ", headers=" + headers +
                          ", queryParameters=" + queryParameters +
                          ", pathParameters=" + pathParameters +
                          ", body='" + body + '\'' +
                          ", isBase64Encoded=" + isBase64Encoded +
                          '}';
              }
          
              public String getPath() {
                  return path;
              }
          
              public void setPath(String path) {
                  this.path = path;
              }
          
              public String getHttpMethod() {
                  return httpMethod;
              }
          
              public void setHttpMethod(String httpMethod) {
                  this.httpMethod = httpMethod;
              }
          
              public Map getHeaders() {
                  return headers;
              }
          
              public void setHeaders(Map headers) {
                  this.headers = headers;
              }
          
              public Map getQueryParameters() {
                  return queryParameters;
              }
          
              public void setQueryParameters(Map queryParameters) {
                  this.queryParameters = queryParameters;
              }
          
              public Map getPathParameters() {
                  return pathParameters;
              }
          
              public void setPathParameters(Map pathParameters) {
                  this.pathParameters = pathParameters;
              }
          
              public String getBody() {
                  return body;
              }
          
              public void setBody(String body) {
                  this.body = body;
              }
          
              public boolean getIsBase64Encoded() {
                  return this.isBase64Encoded;
              }
          
              public void setIsBase64Encoded(boolean base64Encoded) {
                  this.isBase64Encoded = base64Encoded;
              }
          }                                      
          import java.util.Map;
          
          public class ApiResponse {
              private Map headers;
              private boolean isBase64Encoded;
              private int statusCode;
              private String body;
          
              public ApiResponse(Map headers, boolean isBase64Encoded, int statusCode, String body) {
                  this.headers = headers;
                  this.isBase64Encoded = isBase64Encoded;
                  this.statusCode = statusCode;
                  this.body = body;
              }
          
              public Map getHeaders() {
                  return headers;
              }
          
              public void setHeaders(Map headers) {
                  this.headers = headers;
              }
          
              public boolean getIsBase64Encoded() {
                  return isBase64Encoded;
              }
          
              public void setIsBase64Encoded(boolean base64Encoded) {
                  this.isBase64Encoded = base64Encoded;
              }
          
              public int getStatusCode() {
                  return statusCode;
              }
          
              public void setStatusCode(int statusCode) {
                  this.statusCode = statusCode;
              }
          
              public String getBody() {
                  return body;
              }
          
              public void setBody(String body) {
                  this.body = body;
              }
          }                                       
        • The following code shows an example of the pom.xml file.
          <?xml version="1.0" encoding="UTF-8"?>
          <project xmlns="http://maven.apache.org/POM/4.0.0"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
              <modelVersion>4.0.0</modelVersion>
          
              <groupId>apiTrigger</groupId>
              <artifactId>apiTrigger</artifactId>
              <version>1.0-SNAPSHOT</version>
              <build>
                  <plugins>
                      <plugin>
                          <groupId>org.apache.maven.plugins</groupId>
                          <artifactId>maven-compiler-plugin</artifactId>
                          <configuration>
                              <source>1.8</source>
                              <target>1.8</target>
                          </configuration>
                      </plugin>
                  </plugins>
              </build>
              <dependencies>
                  <dependency>
                      <groupId>com.aliyun.fc.runtime</groupId>
                      <artifactId>fc-java-core</artifactId>
                      <version>1.0.0</version>
                  </dependency>
              </dependencies>   
          </project>                                        
      • Use the StreamRequestHandler handler.

        To use this handler, you must convert InputStream to the POJO class. The following sample code describes how to use this handler.

        The pom.xml file must be configured in the same way as that of PojoRequestHandler<I, O> handler.

        import com.aliyun.fc.runtime.Context;
        import com.aliyun.fc.runtime.StreamRequestHandler;
        import com.aliyun.fc.runtime.Context;
        import com.google.gson.Gson;
        import java.io.*;
        import java.util.Base64;
        import java.util.HashMap;
        import java.util.Map;
        
        public class ApiTriggerDemo2 implements StreamRequestHandler {
        
            public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) {
                try {
                    // Convert InputStream into a string. 
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                    StringBuffer stringBuffer = new StringBuffer();
                    String string = "";
                    while ((string = bufferedReader.readLine()) != null) {
                        stringBuffer.append(string);
                    }
                    String input = stringBuffer.toString();
                    context.getLogger().info("inputStream: " + input);
                    Request req = new Gson().fromJson(input, Request.class);
                    context.getLogger().info("input req: ");
                    context.getLogger().info(req.toString());
                    String bodyReq = req.getBody();
                    Base64.Decoder decoder = Base64.getDecoder();
                    context.getLogger().info("body: " + new String(decoder.decode(bodyReq)));
        
                    // You can modify your own logic here. 
        
                    // Response parameters 
                    Map headers = new HashMap();
                    headers.put("x-custom-header", " ");
                    boolean isBase64Encoded = false;
                    int statusCode = 200;
                    Map body = new HashMap();
                    Response resp = new Response(headers, isBase64Encoded, statusCode, body);
                    String respJson = new Gson().toJson(resp);
                    context.getLogger().info("outputStream: " + respJson);
                    outputStream.write(respJson.getBytes());
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        outputStream.close();
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            class Request {
                private String path;
                private String httpMethod;
                private Map headers;
                private Map queryParameters;
                private Map pathParameters;
                private String body;
                private boolean isBase64Encoded;
        
                @Override
                public String toString() {
                    return "Request{" +
                            "path='" + path + '\'' +
                            ", httpMethod='" + httpMethod + '\'' +
                            ", headers=" + headers +
                            ", queryParameters=" + queryParameters +
                            ", pathParameters=" + pathParameters +
                            ", body='" + body + '\'' +
                            ", isBase64Encoded=" + isBase64Encoded +
                            '}';
                }
        
                public String getBody() {
                    return body;
                }
            }
        
            // Function Compute returns responses to API Gateway in the following JSON format. 
            class Response {
                private Map headers;
                private boolean isBase64Encoded;
                private int statusCode;
                private Map body;
        
                public Response(Map headers, boolean isBase64Encoded, int statusCode, Map body) {
                    this.headers = headers;
                    this.isBase64Encoded = isBase64Encoded;
                    this.statusCode = statusCode;
                    this.body = body;
                }
            }
        }                                        

Test a function

After you write a function, you must debug it to verify whether the code is correct. When API Gateway triggers a function, information from API Gateway is sent to the function in the form of the event parameter, which is an input parameter. You can use the information in the event parameter from API Gateway to test whether your function code is correct.

  1. On the Function Details page, click the Function Code tab, and then click the xialatubiao icon. From the drop-down list, select Configure Test Parameters.
  2. In the Configure Test Parameters dialog box, click the Create New Test Event or Edit Existing Test Event tab, and specify the Event Name and event content. Click OK.
    Sample code of event:
    {
        "path":"api request path",
        "httpMethod":"request method name",
        "headers":{all headers,including system headers},
        "queryParameters":{query parameters},
        "pathParameters":{path parameters},
        "body":"string of request payload",
        "isBase64Encoded":"true|false, indicate if the body is Base64-encode"
    }  
    Note
    • If the value of isBase64Encoded is true, the body content that API Gateway sends to Function Compute is Base64-encoded. Function Compute decodes the body content from Base64 format before the content is processed.
    • If the value of isBase64Encoded is false, API Gateway does not perform Base64 encoding on the body content. Function Compute can directly obtain the body content.
  3. On the function details page, click the Function Code tab, and then click Test Function.

Check the result

On the Function Code tab, you can view a successful command.

result
Function Compute sends the execution result to API Gateway for parsing in the following JSON format. The following code shows an example of the response:
{
    "isBase64Encoded":true|false,
    "statusCode":httpStatusCode,
    "headers":{response headers},
    "body":"..."
}       
Note
  • If the results returned by the Function Compute to API Gateway do not meet the format requirements, API Gateway returns the 503 Service Unavailable error.
  • If the content of the body parameter is in the binary format, you must encode the content in Base64. To encode the content in Base64, you must set isBase 64Encoded to true. If the content of the body parameter is not in the binary format, you do not need to encode the content in Base64. In this case, you must set isBase 64Encoded to false.

FAQ

Error code 503 is returned when function execution is triggered by API Gateway but the function log shows that the function is executed. How do I resolve this issue?

API Gateway requires Function Compute to return responses in a specific format. If the returned result is not in the expected format, API Gateway considers the backend service to be unavailable. For more information about the format requirements of the connection between API Gateway and Function Compute, see the description of event and the format of responses of Function Compute.

How do I set the content type of the returned response?

As shown in the figure, you can specify the content type of a response when you set the API operation. For more information, see Create an API operation with Function Compute as the backend service. content-type

Error code 503 is returned when I use API Gateway to invoke a function that was previously invoked but has not been invoked for a period of time. How do I resolve this issue?

If a function has not been invoked for a period of time, a new execution environment must be prepared when the function is invoked again and a cold start delay is caused. This way, timeout occurs in API Gateway before the invocation is complete. API Gateway considers the backend service to be unavailable. To resolve this issue, set the timeout period of API Gateway to a larger value.

Why are the body parameter of the requests passed from API Gateway to Function Compute encoded in Base64?

The body parameter of the requests is encoded in Base64 to prevent content transmission errors or loss. Bodies in form format transmitted by API Gateway are not encoded in Base64. You must select Input Parameter Mapping in API Gateway when you transmit bodies in form format. We recommend that you check whether the value of isBase64 in event is true before you decode events in the function. If isBase64 is set to true, you must decode the request bodies. For more information about the format of event that is passed to Function Compute by API Gateway, see the description of event format.

References

In addition to the Function Compute console, you can configure triggers in the following ways:
  • Use the Serverless Devs tool to configure triggers. For more information, see Serverless Devs.
  • Configure triggers by using the SDK. For more information, see Supported SDKs.

To modify or delete a created trigger, see Manage triggers.