Function Compute supports API Gateway as the event source. You can specify Function Compute as the backend service of APIs. If you specify Function Compute as the backend service of requests, API Gateway triggers the associated function and the function is executed once. Function Compute returns the execution result to API Gateway. This topic describes how to configure API Gateway to trigger function execution in the Function Compute console, including how to configure the input parameters, write function code, and test the function.

Step 1: Configure the input parameter of the function

When API Gateway triggers a function, information from API Gateway is sent to the function as input parameters in the form of event. You can use the event information from API Gateway to test whether your function code is correct.

  1. On the function details page, click the Code tab and click the xialatubiao icon. From the drop-down list that appears, select Configure Test Parameters.
  2. In the Configure Test Parameters panel, click the Create New Test Event or Modify Existing Test Event tab, and specify Event Name and the event content. After you specify the parameters, 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.

Step 2: Write the function code and test the 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 desired service and click Functions in the Actions column.
  5. On the Functions page, click the function that you want to manage.
    hanshuguanli
  6. On the function details page, click the Code tab, enter function code in the code editor, and then click Save.
    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 Compile and deploy code packages.

      • (Recommended) Use the 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;
                }
            }
        }                                        
  7. On the function details page, click the Code tab and click Test Function.

Step 3: Verify the result

After the function is executed, you can view the result on the Code tab.

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 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 isBase64Encoded 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 isBase64Encoded 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 Trigger event format 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 is the body parameter of the requests passed from API Gateway to Function Compute Base64-encoded?

The body parameter of the requests is Base64-encoded to prevent content transmission errors or loss. Bodies in form format transmitted by API Gateway are not Base64-encoded. 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 Trigger event format.

Additional information

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

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