All Products
Search
Document Center

Function Compute:Handlers

Last Updated:Jul 22, 2024

You can use Java handlers to respond to received events and execute corresponding business logic. This topic describes concepts and features of Java 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 of a function in FC 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 for a function by specifying the Handler parameter in the Function Compute console. Handlers of Java functions follow the [Package name].[Class name]::[Method name] format. For example, if the name of your package is example, the class type is HelloFC, and the method is handleRequest, the handler can be configured as example.HelloFC::handleRequest.

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

Handler interfaces

If you use Java for programming, you must implement the interface class provided by Function Compute. The fc-java-core library defines the following interfaces for handlers:

  • StreamRequestHandler

    Uses streams to receive the input event data and returns responses. You must read input data from input streams and then write execution results to output streams.

  • PojoRequestHandler

    Uses a generic type to receive the input event and returns responses. You can customize types of input and output data of a handler. Both the input and output data must be of the Plain Old Java Object (POJO) type.

StreamRequestHandler

The following sample code shows a simple StreamRequestHandler:

package example;

import com.aliyun.fc.runtime.Context;
import com.aliyun.fc.runtime.StreamRequestHandler;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class HelloFC implements StreamRequestHandler {

    @Override
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
        outputStream.write(new String("hello world").getBytes());
    }
}           
  • Package names and class names

    Java is different from other programming languages in execution methods based on packages. In the preceding sample code, the handler is example.HelloFC::handleRequest. example indicates the package name, HelloFC indicates the class name, and handleRequest indicates the class method.

    Note

    The package name and class name can be customized. However, the names must be consistent with the value of the Handler parameter in the function configurations. For more information about how to configure Handler, see Create an event function.

  • Implemented interfaces

    Your code must implement the interfaces that are predefined by Function Compute. In the preceding sample code, StreamRequestHandler is implemented. The inputStream parameter is the data passed into Function Compute when you invoke a function. The outputStream parameter is used to return execution results of the function.

  • Context

    The Context parameter contains the runtime information of a function, such as the request ID and the temporary AccessKey pair. The type is com.aliyun.fc.runtime.Context. For more information, see Context.

  • Return value

    A function that implements StreamRequestHandler returns execution results by using the outputStream parameter.

  • Interface libraries

    The dependency of the com.aliyun.fc.runtime package can be referenced in the pom.xml file in the following sample code:

    <dependency>
        <groupId>com.aliyun.fc.runtime</groupId>
        <artifactId>fc-java-core</artifactId>
        <version>1.4.1</version>
    </dependency>           

    You can visit the Maven repository to obtain the latest version of the fc-java-core package.

Before you create a function, you must compress the code and its dependency fc-java-core into a JAR file. For more information about how to compress code and dependencies, see Compile and deploy code packages.

PojoRequestHandler

The following sample code shows a simple PojoRequestHandler. The SimpleRequest object must support JSON serialization. For example, you can use POJO.

// HelloFC.java
package example;

import com.aliyun.fc.runtime.Context;
import com.aliyun.fc.runtime.PojoRequestHandler;

public class HelloFC implements PojoRequestHandler<SimpleRequest, SimpleResponse> {

    @Override
    public SimpleResponse handleRequest(SimpleRequest request, Context context) {
        String message = "Hello, " + request.getFirstName() + " " + request.getLastName();
        return new SimpleResponse(message);
    }
}            
// SimpleRequest.java
package example;

public class SimpleRequest {
    String firstName;
    String lastName;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public SimpleRequest() {}
    public SimpleRequest(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}            
// SimpleResponse.java
package example;

public class SimpleResponse {
    String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public SimpleResponse() {}
    public SimpleResponse(String message) {
        this.message = message;
    }
}            

The following sample code describes the input event parameter:

{
  "firstName": "FC",
  "lastName": "aliyun"
}            

Example: Use an HTTP trigger to invoke a function

Sample code

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

HTTPTriggerEvent.java

package example;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Map;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder(setterPrefix = "with")
public class HTTPTriggerEvent {
    private String version;
    private String rawPath;
    private Map<String, String> headers;
    private Map<String, String> queryParameters;
    private RequestContext requestContext;

    @JsonProperty("isBase64Encoded")
    private boolean IsBase64Encoded;
    private String body;

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder(setterPrefix = "with")
    public static class RequestContext {
        private String accountId;
        private String domainName;
        private String domainPrefix;
        private HttpInfo http;
        private String requestId;
        private String time;
        private String timeEpoch;

        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        @Builder(setterPrefix = "with")
        public static class HttpInfo {
            private String method;
            private String path;
            private String protocol;
            private String sourceIp;
            private String userAgent;
        }
    }

}

HTTPTriggerResponse.java

package example;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Map;

import com.fasterxml.jackson.annotation.JsonProperty;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder(setterPrefix = "with")
public class HTTPTriggerResponse {
    private int statusCode;
    private Map<String, String> headers;

    @JsonProperty("isBase64Encoded")
    private boolean IsBase64Encoded;
    private String body;
}

App.java defines the entry class of the function.

App.java

package example;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

import com.aliyun.fc.runtime.Context;
import com.aliyun.fc.runtime.PojoRequestHandler;

/**
 * HTTP Trigger demo
 *
 */
public class App implements PojoRequestHandler<HTTPTriggerEvent, HTTPTriggerResponse> {

    @Override
    public HTTPTriggerResponse handleRequest(HTTPTriggerEvent request, Context context) {
        context.getLogger().info("Receive HTTP Trigger request: " + request.toString());
        String requestBody = request.getBody();
        if (request.isIsBase64Encoded()) {
            requestBody = new String(java.util.Base64.getDecoder().decode(request.getBody()), StandardCharsets.UTF_8);
        }
        String message = "HTTP Trigger request body: " + requestBody;
        context.getLogger().info(message);
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "text/plain");
        return HTTPTriggerResponse.builder().withStatusCode(200).withHeaders(headers).withBody(request.getBody())
                .withIsBase64Encoded(request.isIsBase64Encoded()).build();
    }
}

In this example, in addition to the fc-java-core library, the jackson and lombok libraries must be introduced. You can add this dependency in the Maven settings file pom.xml.

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.16.1</version>
</dependency>
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.30</version>
</dependency>

Before you start

Use the preceding sample code to create a function in a Java runtime and create an HTTP trigger. For more information, see Create an event function and Configure an HTTP trigger that invokes a function with HTTP requests.

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 Triggers tab to obtain the public endpoint of the HTTP trigger.

  4. Run the following command in curl to invoke the function:

    curl -i "https://dev-jav-test-fc-luiqas****.cn-shanghai.fcapp.run" -d 'hello fc3.0'

    In the preceding command, https://dev-jav-test-fc-luiqas****.cn-shanghai.fcapp.run is the public endpoint of the HTTP trigger.

    The following result is returned:

    HTTP/1.1 200 OK
    Content-Disposition: attachment
    Content-Length: 11
    Content-Type: application/json
    X-Fc-Request-Id: 1-652503f2-afbfd2b1dc4dd0fcb0230959
    Date: Tue, 10 Oct 2023 07:57:38 GMT
    
    hello fc3.0% 
    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, 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 response 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!".

{
    "errorType": "com.fasterxml.jackson.databind.exc.MismatchedInputException",
    "errorMessage": "Cannot construct instance of `example.HTTPTriggerEvent` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('Hello, FC!')\n at [Source: (byte[])\"\"Hello, FC!\"\"; line: 1, column: 1]",
    "stackTrace": [
        "com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)",
        "com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1588)",
        "com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1213)",
        "com.fasterxml.jackson.databind.deser.std.StdDeserializer._deserializeFromString(StdDeserializer.java:311)",
        "com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1495)",
        "com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:207)",
        "com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:197)",
        "com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322)",
        "com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4593)",
        "com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3643)"
    ]
}

Sample programs

Function Compute official libraries contain sample programs that use various types of handlers and interfaces. Each sample program contains methods for easy compilation and deployment. The following items provide examples: