Create an API with AWS Lambda Walkthrough

วันนี้มาเล่าเรื่องการสร้าง API ด้วย AWS Lambda กัน เนื่องจากช่วงปีใหม่พยายามจะสร้าง API ย่อขนาดรูปภาพขนาดใหญ่ แต่ใช้ shared hosting อยู่มันติดปัญหาเรื่อง timeout กะพวก library ต่างๆ ไม่ซัพพอต จะไปเช่า Cloud server/VPS มันก็จะเว่อร์เกินไปเพราะเว็บเล็กนิดเดียว เลยคิดว่าจะลองใช้ Lambda ดู (เผื่อคนไม่รู้ AWS Lambda คือเซอร์วิซที่รันสคริบหรือรันโปรแกรมให้เราโดยคิดค่าบริการตามเวลาที่ใช้งาน ถ้าสคริบคำนวณนานหรือทำงานนาน ก็จะเสียเงินเยอะ แต่ถ้าเวลาที่มันไม่ได้ใช้งาน ก็ไม่ต้องเสียเงิน) จากที่ลองมาเราว่า UI ของ Amazon มันใช้ยากมาก กว่าจะจับทางถูกว่าต้องคอนฟิคอะไรตรงไหนบ้างนี่เสียเวลาเป็นวันๆๆๆ แต่พอทำเป็นแล้วนะ ใช้เวลาไม่ถึง 5 นาทีเองอะ

เข้าไปหน้าหลักของ AWS Lambda แล้วกดปุ่ม Getting Started สวยๆ ตรงกลางได้เลย ล็อกอินเข้า console ให้เรียบร้อย

หน้าหลัก

พอล็อกอินแล้ว เค้าจะพาเราเข้าสู่ Console ก็หาเมนูที่เขียนว่า Lambda แล้วกระโจนเข้าไปสู่ Lambda Console เลย คลิกปุ่มฟ้าๆ Create a Lambda Function

Lambda Console

เสร็จแล้วเค้าจะให้เราเลือกเทมเพลต (AWS เรียกว่า Blueprint) อันนี้ขอสาธิตการทำ Hello World ง่ายๆ ก่อน คลิกมุมขวาล่าง Hello World (nodejs) เลยค่ะ

เลือก Blueprint Hello World

จากนั้นเค้าจะให้เรากำหนดว่าใช้อะไรเป็นคนเรียกสคริบนี้ เราสามารถเลือกเป็น event ของ AWS Service อื่นๆ ได้ (เช่น ถ้ามีไฟล์ใหม่เข้ามาใน S3 ปุ๊ป ให้มา trigger รันสคริบนี้ เป็นต้น) ในบทความนี้ขอเลือกเป็น API Gateway ซึ่งก็คือใช้ API Gateway (เซอร์วิซอีกตัวของ AWS) เป็นตัวครอบหน้าทำ REST/HTTP API พอมีคนคอล API มาแล้วตัว API Gateway จะมาเรียก Lambda ให้อีกที

เลือกใช้ API Gateway เป็นตัว trigger สคริบ

พอเลือก API Gateway แล้วจะต้อง config ชื่อ, environment, และระดับ security สองอันแรกให้ใช้ค่า default ไปก่อนได้เลย ส่วนอันที่เป็น security มันคือการทำ authentication แบบต่างๆ วันนี้แนะนำให้ใช้ access key ก่อนเพื่อความง่าย (แต่ถ้าเอาง่ายสุด ก็คือไม่ต้องมี security เลยก็ได้นะ แต่ดูไม่ค่อยปลอดภัย เดี๋ยวคนอื่นแฮคยิง API เรารัวๆ เราเสียตังค์บานได้ 55)

คอนฟิค API Gateway นิดๆ หน่อยๆ

จากนั้นไปต่อ จะเจอหน้าให้ตั้งค่าฟังก์ชัน (แต่เราชอบเรียกว่าสคริบมากกว่า) ที่จะรันบน lambda แต่ที่อยากให้ดูคือส่วนที่เป็นโค๊ด ในที่นี้เป็นโค๊ดภาษา javacsript (node.js) ถ้าโค๊ดไม่เยอะมาก console ยอมให้เราสามารถแก้ไขโค๊ดออนไลน์ในนี้ได้เลย แต่ถ้าใหญ่มากๆ จะต้อง zip แล้วอัพโหลดเอานะ

แก้ไขโค๊ดในนี้ได้เลย

อธิบายสั้นๆ คือพอมีตัว trigger เข้ามามันจะไปเรียกฟังก์ชัน exports.handler พร้อมส่งค่าต่างๆ (event, context) เข้ามาด้วย (จะลอง console.log(..) ปริ้นดูก็ได้นะว่าเค้าส่งอะไรมาบ้าง) แล้วพอเราคำนวณเสร็จ ให้เรียกฟังก์ชัน callback พร้อมส่ง result คืนกลับไป

อันนี้ขอให้แก้สคริบเป็นตามนี้ ง่ายๆ เลยคือพอเข้ามาก็ปริ้นท์ event ออกมาดูซะ จากนั้นส่ง static response กลับไปโง่ๆ เป็น JSON ว่า { “result”: “hello world!” }

Important

Point ตรงนี้ที่เราพลาดคือ default function ของ hello world ที่ให้มา มันไม่ได้ส่ง response ที่อยู่ในรูปแบบของ API Gateway ยอมรับได้ คือถ้าเราไม่แก้อะไรแล้วรันไปเลย พอลองยิง API ดูมันจะขึ้นว่า 500 Server Error แม้ว่ามันจะ return ค่าออกไปก็ตาม

'use strict';

console.log('Loading function');

exports.handler = (event, context, callback) => {
    console.log('Received event:', JSON.stringify(event, null, 2));

    callback(null, {
        statusCode: '200',
        body: JSON.stringify({result: 'hello world!'}),
        headers: {
            'Content-Type': 'application/json',
        },
    })
};

เอาโค๊ดนี้ไปแปะให้เรียบร้อย แล้วไปต่อโลด

ตั้งค่า role

ส่วนนี้มันจะให้เราสร้าง role ขึ้นมา เป็นพวกการเซ็ต permission ว่าจะใช้ role ไหนมารัน แล้ว role นี้สามารถ access อะไรได้บ้าง ถ้าเพิ่งเริ่มต้นยังไม่รู้ทำอะไร ก็เลือก Create new role แล้วคอนฟิคตามภาพเลย

สร้าง role ใหม่ให้มันหน่อย

ไปต่อ จะเจอหน้าต่างให้ verify config อีกรอบนึง ก็อ่านดูคร่าวๆ ถ้าไม่โอเคก็กลับไปแก้ไข ถ้าโอเคก็ไปต่อ

Review ซักรอบก่อนไปต่อ (กลับมาแก้ไขได้ แต่อาจจะยากนิดนึง 55)

สำเร็จ(ไปครึ่งทาง)แล้ว!

เซฟ URL Endpoint ของ API Gateway เก็บไว้ด้วย เพราะเดี๋ยวต้องใช้

สร้าง lambda เสร็จแล้ว ง่ายนิดเดียว

จากนั้นเราจะกดปุ่ม Test สีน้ำเงินใหญ่ๆ ลองดูก็ได้ พอกดปุ๊ปมันจะขึ้นหน้าต่างให้เราใส่ input ลงไป เนื่องจากฟังก์ชันเราไม่ได้ต้องการ input อะไรเลย จะใส่ว่างๆ ก็ได้ หรือขี้เกียจก็ปล่อยมันยังงี้แหละ แล้วกด Save and Test

ลองรันสคริบเราดูหน่อย ใช้ค่า default ไปเลยง่ายดี

ถ้าไม่มีปัญหาอะไร มันควรจะขึ้นแบบนี้ กล่องบนคือแสดง output ที่ืสคริบคืนออกมา กล่องขวาล่างจะเหมือนเป็น log windows ถ้าเราปริ้นท์อะไรลงไป มันก็จะขึ้นให้ดูในนี้ สังเกตว่ามันขึ้นว่า “Received event:” ซึ่งเราเป็นคนเขียนไว้ในสคริบเองล่ะ (เลื่อนกลับขึ้นไปดูในโค๊ดสิ)

แสดงผลทดสอบการรับสคริบ

คราวนี้ชิ้นใจว่าโค๊ดเรารันใช้งานได้ล่ะ คราวนี้ลองรันผ่าน API ซิ ลองเปิด URL ที่ได้มาจากตอนสร้าง lambda เสร็จบนเว็บเบราเซอร์ มันจะขึ้นแบบนี้

ขึ้น Forbidden เพราะว่าเราตั้งว่าต้องใช้ access key

มันขึ้นแบบนี้เพราะว่าเราไม่ได้ใส่ access key ให้มันนั่นเอง

ต่อไปต้องไปสร้าง access key ให้เราเข้าไปที่ console ของ API Gateway

เข้าไปสร้าง access key ใน API Gateway

พอเข้ามาแล้ว เมนูด้านซ้ายมือ ให้เลือก Usage Plans แล้วกดปุ่ม Create เซ็ตค่าตามต้องการ หรือตามภาพเลยก็ได้ อันนี้ไม่ซีเรียส แล้วแต่ว่าต้องการกำหนดลิมิตว่าให้มีการเรียก API เยอะแค่ไหนในแต่ละวัน/เดือน จากนั้นกด Next ไปต่อโลด

สร้าง Usage Plan ใน API Gateway ก่อน

จากนั้นเค้าจะพาเรามาตั้งค่าว่า Usage Plan ที่สร้างไปเนี่ยจะผูกกับ API ตัวไหน ให้เรากด Add API Stage แล้วเลือก API (ถ้าใช้ค่า default มาโดยตลอด ตรงนี้มันจะชื่อว่า LambdaMicroService แล้วอย่าลืมเลือก Stage เป็น prod (production) แล้วกดปุ่มติ๊กถูกเล็กๆ ก่อนแล้วค่อยกด Next

ผูก usage plan ที่สร้างขึ้นมาใหม่เข้ากับตัว API

มาถึงหน้าที่เราต้องการซักที คือหน้าสร้าง API Key นั่นเอง กด Create API Key and add to Usage Plan (ปุ่มขวานะ) แล้วใส่ชื่อเล่นให้ key มัน ถ้าไม่คิดอะไรก็เลือก Auto Generate แล้วกดสร้างมันเลย

กดให้ถูกปุ่ม เอาปุ่มขวานะ
ตั้งชื่อ ตั้งค่าตามใจชอบ

พอสร้างเสร็จ จะขึ้นหน้าจอแบบนี้ ให้เราคลิกไปที่ชื่อคีย์ที่เพิ่งสร้างมา มันจะขึ้นรายละเอียด แล้วมีลิงก์เล็กๆ เขียนว่า Show เพื่อขอดู API Key

คลิกที่ชื่อ API Key ที่เพิ่งสร้างตะกี้
คลิกคำว่า Show เพื่อดู​ API Key

พอได้ API Key (ซักที) แล้วคราวนี้ก็ลองยิงโลด เข้า Postman, Curl หรืออะไรก็ได้ตามใจชอบ

  • ใส่ URL เป็น URL เดิมที่ได้จากตอนสร้าง Lambda เสร็จ
  • Header ต้องใส่ api-key ตามภาพเลย
  • ยิง GET, POST, PUT ก็ได้ตามสบาย (ถ้าอยากเซ็ตให้ใช้อย่างเดียว ต้องไป configure ที่ API Gateway เอง)
ลองใช้ Postman เรียกดู

สังเกตว่าตัว output ที่ออกมาจาก API Gateway มันจะไม่เหมือน output ที่ออกมาจากตอนรันเทสใน Lambda เพราะว่าตัว API Gateway ต้องการรู้ statusCode ว่า response ที่ออกมามัน valid หรือไม่ ถ้าเราไม่ใส่ statusCode ให้เค้า เค้าจะถือว่าเป็น 500 หมดนะคะ

เท่านี้ก็จบแล้ว หวังว่าคนอ่านคงพอมีไอเดียที่จะไปแก้ไขสคริบ ลองรับ input ดู พอเซ็ตอัพได้แล้ว เหลือว่าอยากทำอะไรก็ง่าย(ขึ้น)แล้ว งานส่วนใหญ่ที่คนใช้กัน (เช่นย่อรูป) ก็มีคนทำเทมเพลต/สคริบไว้รอเรียกใช้แล้ว ส่วนถ้าเราต้องการเรียก external library (เช่นโหลด npm packages ต่างๆ เข้ามาใช้) ก็ต้องรวมสคริบ+lib เป็น zip เดียว ไปอ่านวิธีการสร้าง deployment package ได้ที่นี่เลย