Ditulis oleh Guillaume Laforge, Developer Advocate for Google Cloud

Dengan runtime Java 11 versi beta terbaru untuk Google Cloud Functions, developer Java sekarang bisa menulis fungsi menggunakan bahasa pemrograman Java (bahasa yang sering digunakan di perusahaan) selain Node.js, Go, atau Python. Cloud Functions memungkinkan Anda untuk menjalankan beberapa kode secara lokal atau cloud, tanpa menyediakan atau mengelola server: Terapkan kode, dan biarkan platform menangani penskalaan Anda. Cukup fokus pada kode Anda: tangani permintaan HTTP yang masuk atau respons beberapa event cloud, seperti pesan yang datang dari Cloud Pub/Sub atau file baru yang diupload dalam bucket Cloud Storage.

Dalam artikel ini, mari kita berfokus pada bagaimana fungsi terlihat, bagaimana Anda bisa menulis fungsi portabel, cara menjalankan dan men-debug mereka secara lokal atau menerapkannya di cloud atau secara lokal, semua berkat Functions Framework, library open source yang menjalankan fungsi Anda. Namun Anda juga akan belajar tentang framework pihak ketiga yang mungkin Anda kenal, yang memungkinkan Anda membuat fungsi menggunakan paradigma pemrograman umum.

Bentuk fungsi Anda

Ada dua tipe fungsi: Fungsi HTTP, dan fungsi latar belakang. Fungsi HTTP merespons permintaan HTTP yang masuk, sedangkan fungsi latar belakang bereaksi terhadap event yang berhubungan dengan cloud.

Java Functions Framework menyediakan API yang bisa Anda gunakan untuk membuat fungsi, serta invoker yang bisa dipanggil untuk menjalankan fungsi secara lokal di mesin Anda, atau di lingkungan Java 11 mana pun.

Untuk memulai API ini, Anda harus menambahkan dependensi dalam file build. Jika Anda menggunakan Maven, tambahkan tag dependensi berikut di pom.xml:

<dependency>
    <groupId>com.google.cloud.functions</groupId>
    <artifactId>functions-framework-api</artifactId>
    <version>1.0.1</version>
    <scope>provided</scope>
</dependency>

Jika Anda menggunakan Gradle, tambahkan deklarasi dependensi ini di build.gradle:

compileOnly("com.google.cloud.functions:functions-framework-api")

Merespons permintaan HTTP

Fungsi Java yang menerima permintaan HTTP masuk mengimplementasikan antarmuka HttpFunction:

import com.google.cloud.functions.*;
import java.io.*;

public class Example implements HttpFunction {
    @Override
    public void service(HttpRequest request, HttpResponse response)
            throws IOException {
        var writer = response.getWriter();
        writer.write("Hello developers!");
    }
}

Metode service() menyediakan objek HttpRequest dan HttpResponse. Dari permintaan, Anda bisa mendapatkan informasi tentang header HTTP, isi payload, atau parameter permintaan. Kita juga bisa menangani permintaan multi-bagian. Dengan respons, Anda bisa mengatur kode status atau header, menentukan payload isi, dan tipe konten.

Merespons event cloud

Fungsi latar belakang merespons event yang datang dari cloud, seperti pesan Pub/Sub baru, update file Cloud Storage, atau data baru maupun yang diupdate di Cloud Firestore. Sebenarnya ada dua cara untuk mengimplementasikan fungsi tersebut, baik dengan membereskan payload JSON yang mewakili event tersebut, atau dengan memanfaatkan pengelompokan objek, semua berkat library Gson, yang menangani penguraian secara transparan untuk developer.

Dengan RawBackgroundFunction, Anda bertanggung jawab menangani payload JSON-encoded event cloud yang masuk. Anda menerima string JSON, jadi Anda bebas untuk menguraikannya sesuka Anda, dengan parser JSON pilihan Anda:

import com.google.cloud.functions.Context;
import com.google.cloud.functions.RawBackgroundFunction;

public class RawFunction implements RawBackgroundFunction {
    @Override
    public void accept(String json, Context context) {
        ...
    }
}

Namun Anda juga memiliki opsi untuk menulis BackgroundFunction yang menggunakan Gson untuk memisahkan representasi JSON ke dalam class Java (POJO, Plain-Old-Java-Object) yang merepresentasikan payload itu. Untuk itu, Anda harus menyediakan POJO sebagai argumen umum:

import com.google.cloud.functions.Context;
import com.google.cloud.functions.BackgroundFunction;

public class PubSubFunction implements BackgroundFunction<PubSubMsg> {
    @Override
    public void accept(PubSubMsg msg, Context context) {
        System.out.println("Received message ID: " + msg.messageId);
    }
}

public class PubSubMsg {
    String data;
    Map<String, String> attributes;
    String messageId;
    String publishTime;
}

Parameter Context berisi berbagai kolom metadata seperti stempel waktu, tipe event, dan atribut lainnya.

Tipe fungsi latar belakang apa yang harus digunakan? Semua tergantung kontrol yang Anda butuhkan untuk payload yang masuk, atau jika Gson unmarshalling tidak sepenuhnya sesuai dengan kebutuhan Anda. Namun unmarshalling yang tercakup oleh framework ini pasti menyederhanakan penulisan fungsi Anda.

Menjalankan fungsi secara lokal

Coding selalu menakjubkan, tetapi melihat kode benar-benar berjalan pasti jauh lebih menyenangkan. Functions Framework dilengkapi dengan API yang kami gunakan di atas, serta fitur invoker yang bisa Anda gunakan untuk menjalankan fungsi secara lokal. Untuk meningkatkan produktivitas developer, akan jauh lebih enak menggunakan loop masukan lokal dan langsung di komputer daripada menerapkan setiap perubahan kode yang Anda lakukan ke cloud.

Dengan Maven

Jika Anda membangun fungsi dengan Maven, Anda bisa menginstal plugin Function Maven di pom.xml:

<plugin>
    <groupId>com.google.cloud.functions</groupId>
    <artifactId>function-maven-plugin</artifactId>
    <version>0.9.2</version>
    <configuration>
        <functionTarget>com.example.Example</functionTarget>
    </configuration>
</plugin>

Pada baris perintah, Anda dapat menjalankan:

$ mvn function:run

Anda bisa memberikan parameter tambahan seperti --target untuk menetapkan fungsi berbeda yang akan dijalankan (jika project Anda berisi beberapa fungsi), --port untuk menentukan port yang akan didengarkan, atau --classpath untuk secara eksplisit menyetel classpath yang diperlukan fungsi tersebut untuk berjalan. Ini adalah parameter dari class Invoker esensial. Namun, untuk mengatur parameter ini melalui plugin Maven, Anda harus memberikan properti dengan -Drun.functionTarget=com.example.Example dan -Drun.port.

Dengan Gradle

Dengan Gradle, tidak ada plugin khusus, tetapi Anda bisa dengan mudah mengonfigurasi build.gradle agar dapat menjalankan fungsi.

Pertama, tetapkan konfigurasi khusus untuk invoker:

configurations { 
    invoker
}

Dalam dependensi, tambahkan library Invoker:

dependencies {
    invoker 'com.google.cloud.functions.invoker:java-function-invoker:1.0.0-beta1'
}

Kemudian, buat tugas baru untuk menjalankan Invoker:

tasks.register("runFunction", JavaExec) {
    main = 'com.google.cloud.functions.invoker.runner.Invoker'
    classpath(configurations.invoker)
    inputs.files(configurations.runtimeClasspath, 
                 sourceSets.main.output)
    args('--target', 
         project.findProperty('runFunction.target') ?:        
         'com.example.Example',
         '--port', 
         project.findProperty('runFunction.port') ?: 8080
    )
    doFirst {
        args('--classpath', files(configurations.runtimeClasspath, 
                                  sourceSets.main.output).asPath)
    }
}

Secara default, kode di atas meluncurkan fungsi com.example.Example pada port 8080, tetapi Anda bisa menggantinya di baris perintah, saat menjalankan gradle atau gradle wrapper:

$ gradle runFunction -PrunFunction.target=com.example.HelloWorld \
                     -PrunFunction.port=8080

Berjalan di tempat lain, akan menjadikan fungsi Anda portabel

Yang menarik dari Functions Framework adalah Anda tidak terikat dengan platform Cloud Functions untuk menerapkan fungsi Anda. Selama di lingkungan target, Anda bisa menjalankan fungsi dengan class Invoker, Anda dapat menjalankan fungsi di lingkungan Cloud Run, Google Kubernetes Engine, Knative, di cloud lain saat Anda bisa menjalankan Java, atau secara umum di semua server secara lokal. Ini membuat fungsi Anda sangat portabel di semua lingkungan. Mari kita lihat lebih dekat penerapannya sekarang.

Menerapkan fungsi Anda

Anda juga bisa menerapkan fungsi dengan plugin Maven, dengan berbagai parameter yang bisa disesuaikan untuk menetapkan region, ukuran memori, dll. Namun di sini, kita akan fokus menggunakan cloud SDK, dengan baris perintah gcloud, untuk menerapkan fungsi-fungsi kita.

Misalnya, untuk menerapkan fungsi HTTP, Anda harus mengetik:

$ gcloud functions deploy exampleFn \
    --region europe-west1 \
    --trigger-http \
    --allow-unauthenticated \
    --runtime java11 \
    --entry-point com.example.Example \
    --memory 512MB

Untuk fungsi latar belakang yang akan diberi tahu tentang pesan baru pada topik Pub/Sub, Anda harus meluncurkan:

$ gcloud functions deploy exampleFn \
    --region europe-west1 \
    --trigger-topic msg-topic \
    --runtime java11 \
    --entry-point com.example.PubSubFunction \
    --memory 512MB

Perhatikan bahwa penerapannya juga memiliki dua varian, meskipun perintah di atas sama: fungsi diterapkan dari sumber dengan pom.xml dan dibangun di Google Cloud, tetapi saat menggunakan fitur build selain Maven, Anda juga bisa menggunakan perintah yang sama untuk menerapkan pre-compiled JAR yang berisi implementasi fungsi. Tentu saja, Anda harus membuat JAR itu terlebih dahulu.

Bagaimana dengan bahasa dan framework lain?

Sejauh ini, kami membidik Java dan Functions Framework biasa, tetapi Anda pasti bisa menggunakan bahasa JVM alternatif seperti Apache Groovy, Kotlin, atau Scala, dan framework pihak ketiga yang terintegrasi dengan Cloud Functions seperti Micronaut dan Spring Boot!

Fungsi Groovy yang menarik

Tanpa membahas semua kombinasi tersebut, mari kita lihat dua contoh berikut. Terlihat seperti apa fungsi HTTP di Groovy?

Langkah pertama adalah menambahkan Apache Groovy sebagai dependensi pada pom.xml:

<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>3.0.4</version>
    <type>pom</type>
</dependency>

Anda juga memerlukan plugin compiler GMaven untuk mengompilasi kode Groovy:

<plugin>
    <groupId>org.codehaus.gmavenplus</groupId>
    <artifactId>gmavenplus-plugin</artifactId>
    <version>1.9.0</version>
    <executions>
        <execution>
            <goals>
                <goal>addSources</goal>
                <goal>addTestSources</goal>
                <goal>compile</goal>
                <goal>compileTests</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Saat menulis kode fungsi, cukup gunakan Groovy sebagai ganti Java:

import com.google.cloud.functions.*

class HelloWorldFunction implements HttpFunction {
    void service(HttpRequest request, HttpResponse response) {
        response.writer.write "Hello Groovy World!"
    }
}

Penjelasan yang sama tentang menerapkan atau menjalankan fungsi Anda secara lokal masih berlaku: platform Java juga cukup terbuka untuk bahasa alternatif! Dan builder Cloud Functions akan dengan senang hati membangun kode Groovy Anda di cloud, karena Maven mengizinkan Anda mengompilasi kode ini berkat library Groovy.

Fungsi Micronaut

Framework pihak ketiga juga menawarkan integrasi Cloud Functions khusus. Mari kita lihat Micronaut.

Micronaut adalah “framework full-stack modern berbasis JVM, untuk membangun aplikasi tanpa server dan layanan mikro modular yang mudah diuji”, seperti yang dijelaskan di situsnya. Ia mendukung gagasan fungsi, aplikasi web, dan layanan mikro tanpa server, dan memiliki integrasi khusus untuk Google Cloud Functions.

Selain menjadi framework yang sangat efisien dengan waktu startup super cepat (yang sangat penting, untuk menghindari cold start yang lama pada layanan tanpa server), yang menarik tentang penggunaan Micronaut adalah Anda bisa menggunakan model pemrograman Micronaut sendiri, termasuk Dependency Injection, deklarasi bean yang dikendalikan anotasi, dll.

Untuk fungsi HTTP, Anda bisa menggunakan anotasi @Controller / @Get milik framework, sebagai ganti antarmuka Functions Framework. Jadi sebagai contoh, fungsi HTTP Micronaut akan terlihat seperti:

import io.micronaut.http.annotation.*;

@Controller("/hello")
public class HelloController {

    @Get(uri="/", produces="text/plain")
    public String index() {
        return "Example Response";
    }
}

Ini adalah cara standar Micronaut untuk menetapkan layanan mikro Web, tetapi itu secara transparan dibangun di atas Functions Framework untuk menjalankan layanan ini sebagai Cloud Function. Selain itu, model pemrograman yang ditawarkan Micronaut bersifat portabel di lingkungan lain, karena Micronaut berjalan dalam banyak konteks yang berbeda.

Yang terakhir tetapi tidak kalah pentingnya, bila Anda menggunakan project Micronaut Launch (di-host di Cloud Run) yang membuat Anda bisa membangun project-project baru dengan mudah (dari baris perintah atau UI), Anda dapat memilih untuk menambahkan modul pendukung google-cloud-function, bahkan memilih bahasa favorit, fitur build, atau framework pengujian:

Micronaut Launch

Pastikan memeriksa dokumentasi dukungan Micronaut Cloud Functions, dan dukungan Spring Cloud Function.

Apa berikutnya?

Sekarang giliran Anda mencoba Cloud Functions for Java 11 hari ini, dengan bahasa JVM favorit atau framework pihak ketiga. Baca panduan memulai, dan coba secara gratis dengan uji coba gratis Google Cloud Platform. Jelajahi fitur dan kasus penggunaan Cloud Functions, lihat quickstart, bahkan berkontribusi untuk open source Functions Framework. Kami menantikan fungsi yang akan Anda bangun di platform ini!