Tutorial Serverless: Membangun API SMS Gateway dengan Bash

5 min read

Disclaimer
Saya bekerja di AWS, semua opini adalah dari saya pribadi. (I work for AWS, my opinions are my own.)
Tutorial Serverless: Membangun API SMS Gateway dengan Bash
Photo by Jonas Leupe on Unsplash

TeknoCerdas.com – Salam cerdas untuk kita semua. Masih melanjutkan tutorial anti-mainstream sebelumnya tentang Bash. Kali ini adalah Tutorial serverless: Membuat API SMS Gateway dengan Bash.

API yang dibuat dapat diakses melalui protokol HTTP dengan method POST. Parameter yang harus dikirimkan adalah sebuah JSON payload yang berisi pesan dan nomor telepon. Berikut contoh API yang akan dibuat.

curl -X POST \
> -H 'Content-Type: application/json' \
> -d '{ "message": "Hello SMS", "phone": "+628123456XYZ" }' \
> END_POINT_URL

Dalam membangun serverless API ini kita akan menggunakan layanan dari AWS yaitu Lambda, SNS dan API Gateway. Ketiganya sebagai platform untuk membangun API SMS Gateway kali ini.

Karena yang kita butuhkan hanyalah Bash maka kita akan menggunakan custom runtime pada AWS Lambda dan beberapa aplikasi command line tambahan seperti AWS CLI dan jq untuk melakukan parsing JSON.

Daftar Isi

Persiapan API SMS Gateway

Sebelum mulai membuat API SMS gateway menggunakan Bash 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 SNS dan Credit anda cukup untuk mengirimkan pengiriman SMS
  • Memiliki pemahaman dasar tentang HTTP dan JSON
  • Memiliki pemahaman dasar tentang Bash atau 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 Lambda Layer untuk AWS CLI dan jq

Terdapat beberapa aplikasi atau utilitas yang kita butuhkan yaitu AWS CLI untuk mengirim SMS dan jq melakukan parsing JSON.

Karena yang kita pakai adalah Lambda custom runtime secara default keduanya tidak ada pada runtime Amazon Linux yang digunakan. Untuk itu kita perlu memasangnya sendiri.

Disinilah peran Lambda Layer. Ketika kita menggunakan sebuah custom runtime maka tools yang tidak tersedia harus kita pasang sendiri.

Lambda Layer menghindarkan kita dari proses instalasi yang berulang-ulang pada waktu fungsi dieksekusi. Ini karena utilitas yang dibutuhkan sudah dimasukkan pada Lambda Layer yang otomatis dimasukkan ke dalam fungsi Lambda yang dieksekusi.

Lambda Layer dapat kita analogikan sebagai “base image” dari OS. Ketergantungan yang dibutuhkan sebuah fungsi dimasukkan pada layer.

Baik, mari kita mulai membuat Lambda layer yang berisi AWS CLI dan jq. Untuk menghemat waktu kita akan memanfaatkan layer yang sudah dipublikasikan oleh orang lain. Daftar Lambda Layer dapat kita lihat pada halaman layanan AWS Serverless Application Repository.

  1. Masuk ke halaman Serverless Application Repository
  2. Masuk ke halaman “Available Applications” pada menu sebelah kiri
  3. Pada kotak pencarian ketik “awscli” kemudian klik “lambda-layer-awscli” yang dipublikasikan oleh Pahud Hsieh.
  4. Anda akan otomatis dibawa ke halaman pembuatan fungsi di AWS Lambda. Pada isian application name isikan “lambda-layer-awscli” kemudian klik tombol Deploy.
  5. Setelah itu otomatis anda akan memiliki sebuah Layer bernama “serverlessrepo-lambda-layer-awscli”.

Layer ini akan otomatis melakukan instalasi binary pada /opt/awscli/. File yang akan kita gunakan yaitu /opt/awscli/aws dan /opt/awscli/jq.

Lambda Layer untuk API SMS Gateway dengan Bash
Lambda Layer untuk API SMS Gateway dengan Bash

Membuat IAM Role untuk Eksekusi Lambda

IAM Role yang dibuat akan mengijinkan Lambda untuk melakukan logging ke AWS CloudWatch dan melakukan publish SMS ke AWS SNS. Dengan demikian kita tidak memerlukan adanya ACCESS_KEY_ID dan ACCESS_SECRET_KEY pada fungsi yang dibuat.

  1. Masuk ke halamn Identity Access Management (IAM)
  2. Masuk ke halaman Role kemudian klik tombol Create Role untuk membuat Role baru
  3. Pada pilihan Choose a use case pilih “Lambda”
  4. Lewati pemilihan Policy dengan langsung klik tombol Next: Tags
  5. Lewati dan langsung ke step 4 yaitu Review Role. Pada isian Role name isikan “LambdaBasicExec”
  6. Kemudian klik tombol Create role
  7. Pada daftar Role klik “LambdaBasicExec” yang baru dibuat kemudian tambahkan policy dengan melakukan klik Add inline policy kemudian klik tab JSON. Ketikkan JSON policy seperti berikut.
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "sns:Publish"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
  1. Klik tombol Review policy kemudian pada isian Name isikan “Lambda-Allow-Logs-SNS” akhiri dengan Create policy.
IAM Role Policy untuk eksekusi Lambda
IAM Role Policy untuk eksekusi Lambda

Dengan policy diatas maka fungsi Lambda yang dibuat dapat menulis ke CloudWatch dan dapat melakukan aksi “publish” di AWS SNS untuk mengirimkan SMS.

Membuat Fungsi di AWS Lambda

Karena kita menggunakan Bash yang tidak didukung secara default oleh Lambda, maka kita akan gunakan custom runtime. Masuk ke console AWS Lambda dan buat sebuah fungsi baru dengan kriteria berikut.

  1. Function Name: “BashSMSApi”
  2. Runtime: “Use default bootstrap”.
  3. Execution Role: “Use existing role” dan pilih “LambdaBasicExec” yang dibuat pada langkah sebelumnya.

Langkah berikutnya adalah melakukan editing file yang diperlukan. Tapi sebelumnya mari kita ubah nama file hello.sh menjadi functions.sh agar lebih sesuai konteks.

  1. Pada daftar fungsi yang ada klik “BashSMSApi” untuk masuk ke halaman editor.
  2. Pada window Function Code klik kanan hello.sh lalu ganti menjadi functions.sh
  3. Konfigurasi dari Handler juga harus diubah dari hello.handler menjadi functions.handler.

Perubahan tersebut berarti ketika Lambda BashSMSApi dijalankan ia akan memanggil fungsi handler()didalam file functions.sh.

Langkah selanjutnya adalah memasang Lambda Layer pada fungsi BashSMSApi yang telah dibuat. Caranya sederhana seperti berikut.

  1. Pada Designer window pilih Layers dibawah BashSMSApi
  2. Scroll kebawah kemudian tekan Add a Layer
  3. Pada pilihan Layer Selection pilih Select from list of runtime compatible layers
  4. Pada Name pilih “serverlessrepo-lambda-layer-awscli” dan Version 1.
  5. Tekan tombol Add untuk menambahkan Layer.
Menambahkan Lambda Layer pada BashSMSApi
Menambahkan Lambda Layer pada BashSMSApi

Ini adalah bagian utama dari tutorial ini yaitu menulis kode API SMS Gateway. Pada AWS Lambda code editor klik ganda file functions.sh lalu ketik kode dibawah ini.

#!/bin/bash
#
# We are using lambda-layer-awscli from Serverless Aplication Repo
# https://us-east-2.console.aws.amazon.com/lambda/home?region=us-east-2#/create/app?applicationId=arn:aws:serverlessrepo:us-east-1:903779448426:applications/lambda-layer-awscli
export PATH=/opt/awscli:$PATH

function handler()
{
    local EVENT_DATA="$1"

    local MSG=$( echo "${EVENT_DATA}" | jq -r '.body | fromjson | .message' | tr -d '\n' )
    local PHONE=$( echo "${EVENT_DATA}" | jq -r '.body | fromjson | .phone' )

    # We are using us-east-1 because SMS feature is not available in some region
    aws sns publish --region us-east-1 --phone-number "$PHONE" --message "$MSG"
}

Apakah kodenya hanya itu? Ya hanya itu. Sangat sederhana bukan? Yang kita lakukan pada dasarnya hanyalah melakukan parsing JSON message dan phone untuk kemudian kita teruskan ke AWS CLI. Pengiriman SMS akan dihandle oleh AWS CLI melalui sub-perintah sns publish.

Ketika Lambda dijalankan maka file yang dijalankan adalah bootstrap yang didalamnya otomatis memanggil file functions.sh. Pada file disebut terakhir terdapat fungsi handler() yang memproses event data yang dikirimkan oleh API Gateway.

fromjson pada jq berfungsi untuk melakukan parsing JSON string. Ingat bahwa body pada event data yang dikirimkan oleh API Gateway berbentuk string of JSON bukan JSON. Jadi dilakukan reparsing terlebih dahulu dengan fromjson.

Disini saya menggunakan hard coded us-east-1 karena tidak semua region dapat melakukan pengiriman SMS. Berdasarkan pengalaman penlis sneidri yang sudah terbukti paling bisa diandalkan dan lancar adalah region us-east-1.

Response dari API ini adalah sama dengan response dari AWS CLI sub-perinah sns publish. Contoh JSON output dari API jika proses pengiriman sukses seperti berikut.

{
    "MessageId": "64efb5fb-9110-5842-a36a-e2c0de736964"
}

Deploy 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.

  1. Pada trigger pilih “API Gateway”
  2. API: “Create an API” untuk membuat API Gateway baru
  3. API type: “HTTP API”
  4. Security: “Open”
  5. API name: “BashSMSApi-API”
  6. Deployment stage: “$default” (dengan dollar didepan)
  7. Centang “Cross-origin resource sharing (CORS)”

Klik tombol Add untuk membuat API Gateway. Anda dapat melihat URL API endpoint dari API Penghitung Kata pada bagian bawah halaman. Contoh pada URL pada akun saya adalah https://6f1rmsrm4i.execute-api.us-west-1.amazonaws.com/BashSMSApi.

Test API SMS Gateway

Untuk melakukan test kita cukup menggunakan utilitas CLI seperti curl Kita akan membuat dulu sebuah fungsi sederhana pada Shell untuk membuat One Time Password (OTP) sepanjang 5 karakter. Kita aliaskan fungsi tersebut dengan nama gen_otp.

$ alias gen_otp='alias gen_otp='LC_ALL=C tr -dc 0-9 < /dev/urandom | head -c 5'
$ gen_otp; echo
93743
$ gen_otp; echo 
16252

Sebagai contoh kita akan coba nomor mengirim SMS berisi OTP menggunakan perintah dibawah ini.

$ cat < {
>    "message": "OTP adalah RAHASIA. JANGAN berikan pada SIAPA PUN. Nomor OTP anda adalah $( gen_otp)",
>    "phone": "+628123456XYZ"
> }
> EOF
{
    "MessageId": "6553572d-5f8e-5d12-97a4-0016102182f0"
}
API SMS Gateway OTP SMS
Contoh pesan SMS yang diterima

Berdasarkan pengujian yang penulis lakukan pengiriman SMS memakan waktu antara 1 sampai 3 detik sejak response sukses dari API. Penulis menggunakan provider Kartu Halo dan nama sender dari SMS adalah TLNET. Mungkin bisa berbeda untuk provider lain.

PENTING: Secara default setiap akun AWS memiliki limit pengiriman SMS sebesar $1 dollar per bulan. Untuk meningkatkan batasan itu anda harus membuka support tiket dengan memberikan keterangan berapa limit yang diinginkan misal $200 dollar per bulan. Tentu harus disertai dengan contoh kasus bagaimana SMS itu akan digunakan.