ใน Codelab นี้คุณจะได้เรียนรู้การสร้าง LINE Chatbot สำหรับแจ้งสถานะการส่งพัสดุแบบ Real Time ผ่าน REST API ของไปรษณีย์ไทย (ThailandPost)
จุดเริ่มขบวนสำหรับการพัฒนาแอปพลิเคชันต่างๆบนแพลตฟอร์มของ LINE คือคุณจะต้องสมัครเป็น LINE Developer ก่อน
Provider คือชื่อผู้ให้บริการ ซึ่งจะไปแสดงตามหน้า consent ต่างๆ หรือเรียกได้ว่าเป็น superset ของแอปทั้งหลายที่เราจะพัฒนาขึ้นรวมถึง LIFF app ด้วย โดยการสร้างเพียงให้ระบุชื่อของ Provider ลงไป ซึ่งอาจจะตั้งเป็นชื่อตัวเอง, ชื่อบริษัท, ชื่อทีม หรือชื่อกลุ่มก็ได้
Channel เปรียบเสมือนแอป หรือเรียกได้ว่าเป็น subset ของ Provider โดยมีอยู่ 3 รูปแบบ คือ LINE Login, Messaging API และ Clova Skill
เบื้องหลังของ Chatbot ตัวนี้ เราจะใช้บริการใน Firebase อย่าง Cloud Functions for Firebase และ Cloud Firestore ดังนั้นขั้นตอนนี้เราจะมาสร้างโปรเจค Firebase เพื่อใช้งานกัน
เนื่องจาก Cloud Functions for Firebase มีเงื่อนไขว่า หากต้องการไป request ตัว APIs ที่อยู่ภายนอก Google คุณจำเป็นจะต้องใช้ Blaze plan(เราจะต้องไปเรียก Messaging API ของ LINE)
Firebase CLI เป็นเครื่องมือที่จำเป็นสำหรับการ deploy ตัวฟังก์ชันที่เราพัฒนาขึ้น อีกทั้งยังสามารถจำลองการทำงานฟังก์ชัน(Emulate) ภายในเครื่องที่เราพัฒนาอยู่(Locally) ได้
npm install -g firebase-tools
Caution: หากคุณพบปัญหาในการติดตั้ง Firebase CLI แบบ globally คุณจำเป็นตัองตั้งค่า npm permission ซะก่อน
firebase --version
firebase login
mkdir bot
cd bot
firebase init functions
สำหรับใครที่มี account บนเว็บไปรษณีย์ไทยแล้วให้เข้าไปที่ หน้า Sign in แล้ว Sign in ได้เลย
สำหรับใครที่ยังไม่มี account สามารถไปสมัครสมาชิกได้ที่ หน้า Register ครับ
หลังจาก Login เข้าระบบของไปรษณีย์ไทยมาแล้ว ขั้นตอนนี้เราจะทำการ create API token เพื่อเอาไปใช้งานตอนเรียก API
Create token
ขั้นตอนนี้เราจะมาสร้าง Utility Class ที่ชื่อว่า thailandpost.js ที่จะคอยช่วยจัดการเชื่อมต่อกับ API ของ ThailandPost โดยจะจัดการสร้าง Token และ ดึงรายการสถานะการส่งของ
package.json
ขี้นมาaxios
ลงไปใน dependencies
"dependencies": {
"axios": "^0.21.1",
"firebase-admin": "^9.9.0",
"firebase-functions": "^3.14.1"
},
functions
จากนั้นสั่ง Install ตัว dependencies ที่เพิ่มเข้ามาใหม่ใน terminal ด้วยคำสั่งnpm install
thailandpost.js
ในโฟลเดอร์เดิมที่ชื่อ functions
และเขียนโค้ดตามตัวอย่างด้านล่างconst axios = require("axios");
class Thailandpost {
constructor() {
// Token ที่ได้จาก ThailandPost
this.token = 'xxxxxxxxx';
}
async getAuthToken() {
let result = null
await axios({
url: 'https://trackapi.thailandpost.co.th/post/api/v1/authenticate/token',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token ' + this.token
}
}).then((response) => {
result = response.data
}).catch((error) => {
result = null
})
console.log("Token is ready!");
return result
}
async getItemTrack(trackNo) {
const authToken = await this.getAuthToken()
const params = {
"status": "all",
"language": "TH",
"barcode": [trackNo]
}
let result = null
await axios({
url: 'https://trackapi.thailandpost.co.th/post/api/v1/track',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token ' + authToken.token
},
data: params
}).then((response) => {
result = response.data
}).catch((error) => {
result = null
})
return result
}
}
module.exports = new Thailandpost();
ขั้นตอนนี้เราจะมาสร้างไฟล์สำหรับเก็บข้อความตอบกลับหาผู้ใช้บนหน้า Chat
สร้างไฟล์ใหม่ชื่อ message.js
ในโฟลเดอร์เดิมที่ชื่อ functions
และเขียนโค้ดตามตัวอย่างด้านล่าง
exports.trackMainPayload = (postCode, trackItems) => (
{
"type": "flex",
"altText": "สถานะการส่งของ",
"contents": {
"type": "bubble",
"size": "giga",
"body": {
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": `${postCode}`,
"decoration": "none",
"size": "xl",
"weight": "bold"
},
{
"type": "box",
"layout": "vertical",
"contents": trackItems,
"spacing": "sm",
"margin": "md"
}
]
}
}
})
exports.trackMainItem = (detail, bgcolor) => ({
"type": "box",
"layout": "horizontal",
"contents": [
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "box",
"layout": "horizontal",
"contents": [
{
"type": "text",
"text": `${detail.status_date}`
}
]
},
{
"type": "box",
"layout": "horizontal",
"contents": [
{
"type": "text",
"text": `${detail.status_description}`,
"size": "sm"
}
],
"spacing": "none",
"margin": "md"
},
{
"type": "box",
"layout": "horizontal",
"contents": [
{
"type": "text",
"text": `${detail.location}`,
"size": "sm"
},
{
"type": "text",
"text": `${detail.postcode}`,
"size": "sm"
}
],
"spacing": "none",
"margin": "md"
}
]
}
],
"backgroundColor": `${bgcolor}`,
"cornerRadius": "md",
"paddingAll": "10px"
})
exports.trackNotFound = () => ({
type: 'text',
text: 'ไม่พบหมายเลขพัสดุที่ระบุ'
})
ขั้นตอนนี้เราจะมาสร้าง Utility Class ที่ช่วยจัดการส่วนที่เกี่ยวข้องกับ LINE ในการส่งข้อความกลับหาผู้ใช้
สร้างไฟล์ใหม่ชื่อ lineapp.js
ในโฟลเดอร์เดิมที่ชื่อ functions
และเขียนโค้ดตามตัวอย่างด้านล่าง
const axios = require("axios");
const LINE_HEADER = {
"Content-Type": "application/json",
Authorization: "Bearer xxxxxxxx"
}
class lineApp {
async replyMessage(replyToken, message) {
try {
const params = {
replyToken: replyToken,
messages: [message]
}
return await axios({
url: 'https://api.line.me/v2/bot/message/reply',
method: 'POST',
headers: LINE_HEADER,
data: params
}).then((response) => {
result = response.data
}).catch((error) => {
result = null
})
} catch (error) {
console.error(`Delivery to LINE failed (${error})`);
}
}
}
module.exports = new lineApp();
LineWebhook
ในไฟล์ index.js
ที่ทำหน้าที่จัดการรับ Webhook ของผู้ใช้ตามโค้ดด้านล่างconst functions = require("firebase-functions");
const thailandpost = require("./thailandpost");
const lineApp = require("./lineapp");
const msgTemplate = require("./message");
exports.LineWebhook = functions.https.onRequest(async(req, res) => {
let event = req.body.events[0];
if (event.type === 'message' && event.message.type === 'text') {
const postCode = event.message.text;
const result = await thailandpost.getItemTrack(postCode);
let { response } = result;
let { items } = response;
let key = Object.keys(result.response.items);
let payload;
if (items[key[0]].length > 0) {
let trackItems = [];
items[key[0]].forEach(function(detail) {
const bgcolor = (detail.delivery_status == 'S') ? '#ABEBC6' : '#EEEEEE';
const item_temp = msgTemplate.trackMainItem(detail, bgcolor);
trackItems.push(item_temp);
});
payload = msgTemplate.trackMainPayload(postCode, trackItems)
} else {
payload = msgTemplate.trackNotFound()
}
await lineApp.replyMessage(event.replyToken, payload);
return res.status(200).send(req.method);
} else {
return res.status(200).send(req.method);
}
});
firebase deploy --only functions
ยินดีด้วย! ถึงตรงนี้คุณก็มี LINE Chatbot ที่สามารถเช็คสถานะส่งของจากไปรษณีย์ไทย ของคุณเองแล้ว!!!