TeknoCerdas.com – Salam cerdas untuk kita semua. Tulisan ini melanjutkan tulisan sebelumnya yaitu membuat Deno runtime pada AWS Lambda. Pada tulisan ini kita akan membuat API menggunakan Deno pada AWS Lambda dan API Gateway.
API yang dibuat adalah sebuah API sederhana untuk membalik urutan huruf yang dikirimkan melalui HTTP POST. Berikut contoh request yang akan diterima oleh API.
$ curl -X POST \
> -H 'Content-Type: application/json' \
> -d '{ "words": "TeknoCerdas" }' \
> END_POINT_URL
API akan ditulis menggunakan Typescript dan dijalankan menggunakan custom Deno runtime yang telah dibuat pada tulisan sebelumnya.
Daftar Isi:
- Persiapan Membuat API Menggunakan Deno
- Membuat Fungsi Lambda Baru untuk Deno API
- Menggunakan Deno Runtime Lambda Layer
- Deploy Deno API Menggunakan API Gateway
- Test Deno API
- Kode Sumber
Persiapan Membuat API Menggunakan Deno
Sebelum mulai membuat API Deno menggunakan AWS Lambda terdapat beberapa prasyarat yang harus anda penuhi.
- Memiliki akun AWS yang aktif
- Memiliki pemahaman dasar tentang AWS Lambda
- Memiliki pemahaman dasar tentang AWS IAM
- Memiliki pemahaman dasar tentang AWS CLI
- Memiliki pemahaman dasar tentang AWS S3
- Memiliki pemahaman dasar tentang HTTP dan JSON
- Memiliki pemahaman dasar tentang Deno dan Shell script
Jika anda tidak memiliki prasyarat diatas silahkan lanjutkan membaca. Karena mungkin banyak informasi baru yang diperoleh meskipun tanpa mencoba langsung tutorial ini.
Membuat Fungsi Lambda Baru untuk Deno API
Pada bagian ini kita akan membuat fungsi Lambda yang akan menggunakan Deno runtime yang disediakan oleh Lambda Layer yang dibuat pada tulisan sebelumnya.
- Masuk pada halaman Functions pada console AWS Lambda
- Tekan tombol Create Function untuk membuat Lambda baru
- Pada Function Name isikan nama API sebagai contoh “MyDenoAPI”
- Pada pilihan Runtime gunakan “Use default bootstrap”
- Pada Execution role pilh “Create a new role with basic Lambda permissions”. Permission ini diperlukan agar Lambda dapat melakukan logging ke CloudWatch.
- Akhiri dengan menekan tombol Create function.
Langkah berikutnya adalah melakukan editing file yang diperlukan. Tapi sebelumnya mari kita ubah nama file hello.sh
menjadi Typescript file yaitu main.ts
.
- Pada daftar fungsi yang ada klik “MyDenoAPI” untuk masuk ke halaman editor.
- Pada window Function Code klik kanan
hello.sh
lalu ganti menjadimain.ts
. - Konfigurasi dari Handler juga harus diubah dari
hello.handler
menjadimain.handler
.
Kita akan mengubah bootstrap bawaan dari Lambda dengan milik kita sendiri. File bootstrap
adalah file entry point yang akan dieksekusi pertama kali oleh Lambda. File bootstrap dapat berupa file binary atau sebuah shell script.
Menulis File Bootstrap
File bootstrap yang kita tulis berfungsi untuk memanggil Deno runtime yang berlokasi di /opt/bin/deno
. Runtime deno tersebut hanya tersedia jika menggunakan Lambda Layer yang dibuat pada tulisan sebelumnya.
File bootstrap akan mengeksekusi Deno dan akan menjalankan Typescript file main.ts
.
#!/bin/bash
# Resolve to /opt/bin/deno
export PATH=/opt/bin:$PATH
# Handler format: .
#
# The script file .sh must be located at the root of your
# function's deployment package, alongside this bootstrap executable.
# Split filename and function name using '.'
# 0 => File name, 1 => Func name (not used)
IFS="." read -ra FN <<< "$_HANDLER"
# Cached files will be saved to DENO_DIR
[ -z "$DENO_DIR" ] && export DENO_DIR=/tmp/deno_dir
[ -z "$NO_COLOR" ] && export NO_COLOR=true
deno run --allow-read --allow-net --allow-env "${FN[0]}.ts"
Menulis Typescript File main.ts
File Typescript ini adalah file utama yang berisi logika untuk memproses JSON payload yang dikirimkan dan membalik susunan huruf yang ada.
/**
* Declare minimal interfaces for properies that used in Lambda
*/
interface RequestBody {
words: string;
}
interface ResponseMeta {
ip_addr: string;
user_agent: string;
}
interface ResponseBody {
original: string;
reversed: string | null;
meta: ResponseMeta;
}
interface LambdaEvent {
body: string;
}
interface HttpContext {
sourceIp: string;
userAgent: string;
}
interface LambdaContextHttp {
identity: HttpContext;
}
/**
* Main handler for Lambda event and request context
*/
async function handler(lambda_event: LambdaEvent, lambda_context: LambdaContextHttp) {
// Get request body
let body: RequestBody = JSON.parse(lambda_event.body);
let response: ResponseBody = {
reversed: null,
original: body.words,
meta: {
ip_addr: lambda_context.identity.sourceIp,
user_agent: lambda_context.identity.userAgent
}
};
try {
response.reversed = body.words.split('').reverse().join('');
} catch (e) {}
return JSON.stringify(response);
}
async function lambda_main_loop()
{
const AWS_LAMBDA_RUNTIME_API = Deno.env.get('AWS_LAMBDA_RUNTIME_API');
const LAMBDA_BASE_URL = "http://" + AWS_LAMBDA_RUNTIME_API + "/2018-06-01/runtime/invocation";
let resp: Response | null = null;
while (true) {
try {
resp = await fetch(LAMBDA_BASE_URL + "/next", {
headers: {
'Content-Type': 'application/json'
}
});
const evt = await resp.json();
const invocation_id = resp.headers.get('Lambda-Runtime-Aws-Request-Id');
const http_context = {
identity: {
sourceIp: evt.requestContext.http.sourceIp,
userAgent: evt.requestContext.http.userAgent,
}
}
const handler_resp = await handler(evt, http_context);
resp = await fetch(LAMBDA_BASE_URL + "/" + invocation_id + "/response", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: handler_resp
});
if (!resp.ok) { console.error(resp) };
} catch (e) {
console.error(e);
}
}
}
// Run from AWS Lambda
if (Deno.env.get('AWS_LAMBDA_RUNTIME_API')) {
lambda_main_loop();
}
// Run from CLI
if (!Deno.env.get('AWS_LAMBDA_RUNTIME_API')) {
const decoder = new TextDecoder('utf-8');
const json_input = JSON.parse(decoder.decode(Deno.readFileSync('./event.json')));
// console.log(json_input);
const evt = {
body: json_input.body
};
const ctx = {
identity: {
sourceIp: json_input.requestContext.http.sourceIp,
userAgent: json_input.requestContext.http.userAgent
}
};
const output = await handler(evt, ctx);
console.log(output);
}
Terdapat fungsi lambda_main_loop()
yang berfungsi untuk melakukan komunikasi ke AWS Lambda. Secara terus menerus fungsi tersebut akan 1) Mengambil request dari Lambda 2) Memproses request tersebut 3) Mengirimkan hasilnya kembali ke Lambda.
Response JSON yang dikembalikan oleh fungsi ini tidak hanya teks yang dibalik tapi juga IP address dan User Agent.
{
"reversed": "0202 moc.sadreConkeT",
"original": "TeknoCerdas.com 2020",
"meta": {
"ip_addr": "127.0.0.1",
"user_agent": "curl/7.54.0"
}
}
Menggunakan Deno Runtime Lambda Layer
Sampai disini fungsi Lambda yang dibuat sebelumnya belum bisa dijalankan karena ketergantungan pada file executable /opt/bin/deno
. Fungsi ini harus menggunakan Layer “MyDenoLayer” yang dibuat sebelumnya agar dapat menjalankan runtime Deno.
- Pada Designer window pilih Layers dibawah MyDenoAPI
- Scroll kebawah kemudian tekan Add a Layer
- Pada pilihan Layer Selection pilih Select from list of runtime compatible layers
- Pada Name pilih “MyDenoLayer” dan Version 1.
- Tekan tombol Add untuk menambahkan Layer.
Deploy Deno API Menggunakan API Gateway
Setelah menyelesaikan fungsi pada Lambda langkah berikutnya adalah menghubungkan Lambda dengan API Gateway agar bisa diakses dari internet.
Untuk itu kita perlu menambahkan trigger pada Lambda yang dibuat. Pada window Designer klik tombol Add Trigger dan ikuti langkah berikut untuk menambahkan API Gateway.
- Pada trigger pilih “API Gateway”
- API: “Create an API” untuk membuat API Gateway baru
- API type: “HTTP API”
- Security: “Open”
- API name: “DenoAPI”
- Deployment stage: “$default” (dengan dollar didepan)
- Centang “Cross-origin resource sharing (CORS)”
Klik tombol Add untuk membuat API Gateway. Anda dapat melihat URL API endpoint pada bagian bawah halaman. Contoh sebuah end point dari API Gateway adalah https://RANDOM_STRING.execute-api.us-west-1.amazonaws.com/words.
Test Deno API
Untuk melakukan test kita cukup menggunakan utilitas CLI seperti curl
atau POSTman jika lebih suka menggunakan GUI. Pada test ini JSON payload yang akan dikirimkan seperti berikut.
{
"words": "TeknoCerdas.com Berita Teknologi yang Mencerdaskan"
}
Lakukan HTTP POST pada endpoint URL yang ditampilkan oleh API Gateway.
$ cat < -H "Content-Type: application/json" -d @- \
> 'https://jm8550zz73.execute-api.us-east-1.amazonaws.com/words'
> {
> "words": "TeknoCerdas.com Berita Teknologi yang Mencerdaskan"
> }
> EOF
{
"reversed": "naksadrecneM gnay igolonkeT atireB moc.sadreConkeT",
"original": "TeknoCerdas.com Berita Teknologi yang Mencerdaskan",
"meta": {
"ip_addr": "36.84.145.252",
"user_agent": "curl/7.54.0"
}
}
Dari beberapa kali percobaan penulis waktu yang diperlukan untuk Cold Start dari API sekitar 1 detik. Setelah itu waktu eksekusi Deno API yang dibuat konsisten pada angka 2 – 3 ms. Cukup impresif.
Kode Sumber
Kode sumber untuk tutorial ini dapat anda lihat pada tautan github berikut:
https://github.com/rioastamal-examples/lambda-custom-deno-runtime
Pada kode sumber tersebut terdapat Terraform script yang digunakan untuk membangun semua resources yang dibutuhkan. Juga terdapat kode Typescript untuk API yang digunakan pada tulisan ini.