Photo by Luca Campioni on Unsplash

ออกแบบสร้าง APIs แบบโคตรเร็ว, จัดการเนื้อหาแบบโคตรง่าย ด้วย Strapi Headless CMS

Max Veerapat Kumchom
7 min readJun 1, 2020

--

สวัสดีครับผมแมกซ์นะครับ 😋 เป็นอย่างไรกันบ้างชาว Developer เชื่อว่าหลายๆ คนคง Work From Home กันในช่วงสถานะการ COVID-19 นี้ 😷 สำหรับผมแล้วผลลัพธ์คือเวลานอนที่ลดลงและน้ำหนักที่มากขึ้น 55+ 🤣 เครียดมากเลยมาเขียนบทความนี้จะมาแชร์เครื่องมือที่น่าสนใจในปี 2020 ช่วยเราในการสร้าง APIs ให้ง่ายกว่าที่เคยเป็นมา Strapi Headless CMS บนเทคโนโลยี Node.js นั่นเอง เป็น Open-source ที่ออกแบบมาให้สามารถจะปรับแต่งได้ง่าย เปลี่ยนการเขียน Backend แบบเดิมไปเลย 🤩

Design APIs fast, manage content easily.

Strapi is the leading open-source headless CMS. It’s 100% Javascript, fully customizable and developer-first.

ก่อนที่จะไปทราบว่า Strapi คืออะไร ? ขอเริ่มต้นกันที่คำศัพท์ที่หลายๆคนคุ้นเคย CMS (Content Management System) : ระบบจัดการเนื้อหา แปลตรงตัวเลย 🤗 ถึงตรงนี้ คือแล้วมันยังไงจัดการเนื้อหาอะไรยังไง !?! 😤 ขอยกตัวอย่างเป็น CMS ที่ใครหลายๆคนรู้จัก เช่น Wordpress, Drupal, Joomla และอื่นๆ หรือ ที่เรียกกันว่าเว็บไซต์สำเร็จรูป ติดตั้งแล้วก็สร้างเข้า ไปจัดการข้อมูลเนื้อหา, สร้างหน้า, ลงธีมได้ด้วยตัวเอง โดย CMS จะถูกแบ่งเป็นชนิดต่างๆ ตามการออกแบบและความสามารถของมัน

  • Traditional CMS
  • Decoupled CMS
  • Headless CMS

Traditional CMS : แบบดั้งเดิม คือทุกส่วนจะเป็นระบบเดียวกันมี ฐานข้อมูล, หน้าหลังบ้าน, หน้าหน้าบ้าน ตั้งอยู่บนเซิฟเวอร์เดียวกันพร้อมใช้งาน อย่างเช่น Wordpress ด้วยเทคโนโลยี PHP ที่เป็น Server side rendering 😕

Decoupled CMS : แบบแยกส่วน คือจะคล้ายแบบดั้งเดิมเพิ่มเติมคือ สามารถส่งข้อมูลทาง API ได้ อย่างเช่น Headless WordPress และ Drupal ที่มี REST API ให้ใช้งานด้วย

Headless CMS : แบบไม่มีหัว คือจะคล้ายแบบแยกส่วน แต่ตัดส่วนหัวหรือส่วนหน้าบ้านออกไปเลยนั่นเอง 😧 จะมีเฉพาะสิ่งที่สำคัญคือ APIs ไม่ว่าจะเป็น REST หรือ GraphQL เป็นเทคโนโลยีที่ทันสมัยกว่า CMS ดั้งเดิม อย่างเช่น Strapi, Contentful และ Sanity 😏

แล้วทำไม Strapi CMS Headless ถึงน่าใช้ ? 🤔 ด้วยเทคโนโลยีเป็น Node.js โดยข้างหลังสร้างด้วย Koa (next generation web framework for node.js) ยอดฮิตสำหรับชาว Backend ฝั่ง Node.js หน้าหลังบ้านสร้างด้วย React 😎 ฐานข้อมูลสามารถเลือกได้ตามที่เราถนัดไม่ว่าจะเป็น SQL หรือ NoSQL 😮 ทำให้ Frontend Developer กลายเป็น Fullstack Developer ได้เลย 🧐 เพราะความง่ายของการสร้าง APIs ที่ Strapi มีให้ และด้วยความเคยชินกับการใช้ JavaScript สามารถศึกษาต่อและทำการปรับแต่งตามต้องการได้ 🤠 เรื่องประสิทธิภาพและความปลอดภัย ลดความผิดพลาดในการเขียนขึ้นเอง มีอัพเดทเรื่องความปลอดภัยอย่างสม่ำเสมอ ยืดหยุ่นมากขึ้น มีอิสระในการเลือกออกแบบได้ด้วย Frontend Framework ต่างๆ ตามความชอบของผู้พัฒนา 😲 และที่สำคัญคือ Time-to-Market ในยุคนี้เป็นสิ่งที่เรียกว่าสำคัญอันดับต้นๆเลยทีเดียว ด้วยเครื่องมือที่ง่ายและเร็ว ทำให้เราได้โฟกัสกับตัว Product มากขึ้นและทำให้ Cost เรื่องเวลาและปริมาณผู้พัฒนาต่ำลง 🤑

Strapi Community Edition : วันที่ 26 พฤษภาคม 2020 ได้ประกาศ Stable release ออกมา 🥰 หลังจากเป็น alpha, beta และ rc มาก็นาน โดน COVID-19 นานเข้าไปอีกจาก 5 ปีก่อนและ 3 ปีหลังจากบริษัท Strapi ก่อตั้ง ตอนนี้มี 25,000+ stars บน GitHub และ Global 500 companies (IBM, NASA, Société Générale, Delivery Hero, และอื่นๆ) บริษัทกว่าพันใช้งานบน Production 🤤 ผมก็แอบติดตามมาตลอด เรียกได้ว่าทดลองใช้ตอน Bugs โคตรเยอะ ออกเวอร์ชั่นใหม่ Migrations ทีน้ำตาไหล ตอนนี้ก็ถือว่าพร้อมใช้แล้ว เป็นช่วงที่เรียกได้ว่า โตเป็นวัยรุ่นเลย 😎

ความสามารถต่างๆ ของ Strapi ผมจะอธิบายเป็นคราวๆก่อนนะครับ ว่ามันทำอะไรได้บ้าง ช่วยเราในเรื่องไหนบ้าง หลังจากจบ จะเป็นแชร์ความเข้าใจ เทคนิคต่างๆ หลังจากได้ลองใช้ และศึกษามาบอกเลยปล่อยหมด ยาวๆกันไปเลย 😝

  • Content-Type Builder

ตัวช่วยในการออกแบบโครงสร้างของข้อมูล ซึ่งข้อมูลของเราในการจัดเก็บลง Database ก็จะมีหลายชนิดของข้อมูลอย่าง (Text, Boolean, Number, JSON, Media, UID, etc) 🙀 ตรงนี้ก็จะมีหน้าหลังบ้านนี้ ให้เราได้ทำการออกแบบและสร้าง API ไปในเวลาเดียวกันเลย อารมณ์เหมือนการเขียน ER Diagram และได้เสร็จได้ CURD Operation ใช้งานผ่าน API ได้เลยแถมสร้าง Swagger UI ให้ด้วยนะเออเอาดิ 😇 ทำได้ด้วยยังไม่ต้องเขียนโค้ดสักบรรทัด คลิกไปคลิกมา เสร็จเฉย 😜

  • Content Management

ระบบจัดการเนื้อหา หลังจากที่เราสร้างโครงสร้างของข้อมูลเราเรียบร้อยแล้ว 😌 เราสามารถจัดการเนื้อหา สร้าง, แก้ไข, อ่านและลบ ของเราได้เลย โดยการ Input ข้อมูลต่างๆ ก็จะเปลี่ยนไปตามชนิดของข้อมูลที่เราออกแบบ พร้อมยังมีความสามารถการค้นหาข้อมูลด้วยการกรองได้ 🤤

  • Customizable API

APIs นั้นมีให้เลือกถึงสองอย่างคือ REST และ GraphQL บน Apollo ได้เลย 🤩 แค่ลง Plugins เสริมเข้าไปเท่านั้น กดได้จาก Marketplace ได้เลย

  • JWT authentication

ใช้ระบบการเข้าถึงที่ปลอดภัยและทันสมัยคือ JWT (JSON Web Tokens) หรือ providers อย่าง GitHub, Facebook, Google, Twitter, Discor, Twitch, Instagram และ VK ก็สามารถทำได้เลย 😳

  • Dynamic Zones

ความสามารถสร้างรายการโครงสร้างแบบปรับเปลี่ยนได้ มีประโยชน์กับการนำข้อมูลไปแสดงผลแบบปรับเปลี่ยนได้อย่างเช่น Slider, Quotes และ Meta fields ต่างๆ 😵

  • Webhooks

การสื่อสารกับ Application ต่างๆ เมื่อข้อมูลเปลี่ยนแปลงได้ เช่นไป Trigger ให้ทำการ Build frontend และ Deploy สำหรับพวก Site generator หรือส่ง Notify ไปหา Messaging app 🥳

  • File Storage and Media Library

ระบบจัดการไฟล์นั่นเอง มาช่วยเราอัพโหลดข้อมูลเข้าไปยังระบบ ในการจัดการเนื้อหาประเภท images, videos, audio files, PDFs, or GIFs ไฟล์ประเภท images นั้นสามารถทำ Responsive friendly upload และ Size optimization (without quality loss) 🙄

  • Plug-ins Providers

ระบบ Plugins ที่จะเข้ามาเพิ่มความสามารถให้มากขึ้น โดยพื้นฐานก็จะมีมาให้ก็ถือว่าเพียงพอเลยเช่น ระบบอีเมล, ระบบอัพโหลดไฟล์, ระบบสมาชิกและสิทธิการเข้าถึง, ระบบ APIs และ API Document ในอนาคตมี Plugins มาให้ลงอีกเพียบแน่เลย🤗

ขายของไปเยอะมาลุยกัน 😂 ต่อจากนี้จะเป็นสิ่งที่ผมนำมาแชร์ให้คนที่สนใจและอยากจะทดลองใช้มัน จะเป็นสิ่งที่ผมงง และก็ใช้เวลานานตามอ่าน Blog ดูพวก Youtube ของต่างประเทศกว่าจะเข้าใจมันมาแชร์ ส่วนอื่นที่ไม่มีก็อ่าน Doc เอาเนอะ 😜 Documentation ตอนนี้ค่อนข้างจะสมบูรณ์และเข้าใจง่ายแล้ว เทียบกับตอนแรกๆ ที่ต้องไปตาม Twitter กันเลยทีเดียวเวลามีความสามารถใหม่ๆออก

มาเริ่มด้วยการสร้างโปรเจค บรรทัดเดียวเลย
สิ่งที่คุณต้องมีก็คือ NodeJS >= 10.x, NPM >= 6.x 😙

npx create-strapi-app my-project --quickstart--- or ---yarn create strapi-app my-project --quickstart

โดยการที่ใช้ --quickstart👇 จะทำให้ Strapi เลือก Database เป็น SQLite โดยถ้าเอาออกเราก็จะสามารถเลือกใช้ PostgreSQL, MongoDB, SQLite, MySQL และ MariaDB ตามนี้เลย

หลังจากสร้างโปรเจคเสร็จ มันก็จะเปิด Admin Panel ให้เป็นหน้าหลังบ้านในการจัดการข้อมูล 🤖 ก็ทำการสร้าง admin ในการเข้าใช้งานให้เรียบร้อย เราก็พร้อมแล้ว

สิ่งที่อยากให้ทุกคนลงก็คือ Plugin ไปที่แถบด้านซ้าย GENERAL > Marketplace เลยเพราะสิ่งสำคัญเลยที่ต้องมีและไม่ได้ถูกติดตั้งมาโดย Default คือ Documentation (Swagger UI) และ GraphQL ที่จะทำให้เราสามารถใช้ APIs ได้ 🤩

ใช้อะไรก็ลงได้เลย หลังจากลงแล้วจะทำให้เราได้เมนูเพิ่มเติมขึ้นมาคือ PLUGINS > Documentation นั่นคือ Swagger UI เอาไว้ใช้สำหรับดู Endpoint ต่างๆ Body ต้องประกอบด้วยอะไร สามารถเข้าถึงด้วยการ Open the documentation 🤠

ได้หน้าตาแบบนี้ 😋 ของผมจะแตกต่างหน่อย เพราะว่าผมมีการสร้าง Collections ไว้แล้ว จะเห็นได้ว่ามีมาเพียงพอสำหรับ CURD พื้นฐานแล้ว แถมความสามารถของการ Filters, Sort, Limit และ Start มาให้แล้วในตัว ยังไม่ได้โค้ดเลยนะเออ 🤡 อ่านรายละเอียด Available operators ได้ที่นี่เลย

PLUGINS > Content-Types Builder ตัวช่วยในการออกแบบโครงสร้างของข้อมูล เป็นสิ่งที่เราใช้และต้องทำความเข้าใจกับมันให้ดี 🧐 เพราะมันหมายถึงเรากำลังออกแบบฐานข้อมูลของเรา โดยสามารถสร้างได้ 3 รูปแบบ

  • Collection Type
  • Single Type
  • Components

Collection Type : ชุดข้อมูล การสร้างเนื้อหารูปแบบนี้จะเป็นการสร้างแฟ้มเก็บเอกสารนั่นเอง 😒 ในที่นี้เข้าใจแบบ SQL ก็คือสร้าง Table นั่นแหละครับ ที่สามารถเก็บข้อมูลได้หลายๆ Records ตัวอย่างเช่น Users ที่มันสร้างมาให้เราในตอนเริ่มต้น ข้างใน Users ก็จะประกอบด้วย Fields ของข้อมูลก็คือ Columns แต่ละ Field ก็จะมีชื่อและชนิดของข้อมูลนั่นเอง

โดยถ้าลองทำการเพิ่ม Field ก็จะมีชนิดข้อมูลต่างๆ ให้เราได้เลือก ก็เลือกให้เหมาะสมกับข้อมูลที่ต้องการจะจัดเก็บ 🧔

Single Type : ข้อมูลชุดเดียว เนื้อหารูปแบบนี้จะต่างจาก Collection Type นิดเดียวคือมันมีอันเดียวนั่นเอง 🎅 ส่วนข้างในก็ประกอบด้วย Field เช่นกัน แต่จะไม่สามารถ เพิ่มข้อมูลเข้าไปอีกชุดได้ ทำได้เพียงการแก้ไขและลบ เหมาะสำหรับการออกแบบเอาไว้เก็บข้อมูลที่จะมีเพียงชุดเดียว เช่นการเก็บข้อมูล Home Page Detail, About Us อะไรทำนองนี้ 💁‍♂️

Components : ส่วนประกอบ เนื้อหารูปแบบนี้ค่อยข้างน่าสับสนว่ามันเอาไว้ใช้ยังไง 🤪 ความสามารถก็คือประกอบด้วย Field เช่นกัน แต่ประโยชน์ของมันคือจะ Repeatable คือถ้าเราสร้างมันขึ้นมา แล้วมันก็สามารถเป็น Field ไปอยู่ใน Collection Type ได้ และมีหลายๆอันได้ อ้าว งงในงง 😵 อธิบายยังไงดี ถ้ามองจากสิ่งที่ได้จากการเรียก API มันคือ JSON Arrays นั่นเอง 👽 เพราะที่ผ่านมาเราได้แค่ข้อมูลชนิด Text, Number และอื่นๆ ยกตัวอย่าง มาดูกันให้เห็นภาพ

  1. Collection Type Restaurant ประกอบด้วย Field ที่เป็น Component ที่สามารถ (repeatable) ชื่อ restaurant_hours เท่ากับว่าร้านอาหารที่เราสร้างขึ้น สามารถใส่ข้อมูลเวลาทำการเปิดได้มากกว่า 1 เวลา เช่นทำการใส่วันอาทิตย์ - จันทร์ ร้านปิด, วันอังคาร - ศุกร์ เปิดตอน 12.00 - 22.30 และ วันเสาร์ เปิดตอน 11.30 - 16.00 🤒
  2. Collection Type ชื่อ Order ประกอบด้วย Field ที่เป็น Component ที่สามารถ (repeatable) ชื่อ order_list เท่ากับว่าใบสั่งซื้อจะมีข้อมูลของสินค้า, จำนวน และอื่นๆ แบบเป็นรายการได้ 😹

หวังว่าจะเกทตามที่ผมอธิบาย 😆 แต่ของงี้ต้องลองเล่นครับจะเข้าใจเลย มี Tutorial ให้ทำตามแบบจับมือทำเลย รับรองเข้าใจ 😇

Field ชนิด Relation Field ที่สามารถอ้างถึง Collection Type ได้ ในการสร้างชุดข้อมูล จะสังเกตว่ามี Field ชนิด Relation ให้เลือก แล้วมันใช้ยังไงหล่ะมาดูกัน 😬

มันคือการสร้างความสัมพันธ์ของชุดข้อมูลนั้นเอง จะสามารถเลือกแบบ (One-Way, One-to-One, One-to-Many, Many-to-Many, Polymorphic) 😲 ในที่นี้จะยกตัวอย่าง การสร้างชุดข้อมูลการรีวิวร้านอาหาร

Collection Type ชื่อ Review ประกอบด้วย Field (comment, rating, likes, author, restaurant) โดยการบันทึกการรีวิวร้านอาหารนั้น ก็จะต้องเก็บว่าผู้ใช้นั้นเป็นใคร คอมเม้นว่าอะไร ให้คะแนนเท่าไหร่ และจะต้องสร้าง Relation Field คือ Author ก็คืออ้างถึงไปยัง User นั่นเอง ว่ารีวิวโดยใครแบบนี้

โดยสร้าง Relation Field ชื่อ author เป็นแบบ One-Way คือ Review has one User
รีวิวนั้นมี 1 ผู้ใช้ โดยเบื้องหลังการเก็บข้อมูลก็จะเป็นการเก็บ id ของ User ไว้ใน Collection Review ทำให้เวลาเราดึงข้อมูลจาก API Reviews จากการ GET ก็จะได้ข้อมูลของ User ที่ทำการรีวิวนั้นๆไปด้วย 😮

PLUGINS > Roles & Permissions การกำหนดบทบาทและการสิทธิในการเข้าถึงข้อมูลโดยพื้นฐานจะมี Authenticated สำหรับผู้ใช้ที่ทำการ Register เข้ามาและมี Authorization ประเภท Bearer Token แนบ JWT มากับ Header และ 😼 Public สำหรับผู้ใช้ที่ไม่ได้ทำการ Login เข้าสู่ระบบ โดยเราสามารถเพิ่ม Role ใหม่ๆได้เอง

เราสามารถเข้าไปตั้งค่า Permissions ให้ Role เหล่านั้นได้ตามความเหมาะสม

โดยพื้นฐานจะไม่สามารถใช้ Endpoint ไหนได้เลย 🖐 ก่อนที่เราจะทำการอนุญาติให้ทำได้ก่อน ติด HTTP 403 Forbidden ไป ก็หลังจากสร้าง API แล้วก็อย่าลืมมากำหนดสิทธิให้เรียบร้อยด้วยนะครับ

Authentication การลงทะเบียนและการเข้าใช้งาน สามารถยิงผ่าน API สามารถอ่านเรื่อง Authentication ที่นี่ได้เลย และสามารถทดลองสร้างจาก หน้าหลังบ้านเราได้เลยโดยไปที่ COLLECTION TYPES > Users และไปที่ Add New user เพื่อทำการสร้างผู้ใช้ได้เลย 👨‍👩‍👧

หลังจากทำการ Save เราก็จะได้ User มา 1 คน 👨‍👩‍👧‍👦

ทดลอง Register ผ่าน API

http://localhost:1337/auth/local/register

POST ไปตามนี้เลยโดย Body เป็น Raw JSON ได้ HTTP 200 OK พร้อมกับ Response เป็น JWT ที่ต้องนำไปใช้กับการใช้ API Endpoint อื่นๆ 🏃‍♂️

ทดลอง Login ผ่าน API

http://localhost:1337/auth/local

สิ่งที่ได้จากการ Login ก็เหมือนกับตอน Register เลย 👯‍♂️

ทดลอง GET Restaurants นำ JWT ที่ได้มา แนบ Authorization ประเภท Bearer Token

http://localhost:1337/restaurants

เพียงเท่านี้ก็จะสามารถเข้าถึงชุดข้อมูลของ Restaurants ที่ผมทำการสร้างไว้ได้ 👌

Parameters พารามิเตอร์ สิ่งที่อยากจะฝากเป็นอย่างสุดท้ายแล้วก่อนจากนั้น อยากให้ลองเล่นกันดูว่ามันทำอะไรได้บ้าง 👍 Available operators พวกนี้เป็นประโยชน์มาก โดยความสามารถนี้มีติดมาเลยกับทุก Collection Type

  • Filters ใช้สำหรับการกรองชุดข้อมูลที่เราต้องการกับการใช้ GET เช่น Equals, Less & Greater then, Included, Contains และอื่นๆ
  • Sort ใช้สำหรับเรียงชุดข้อมูลโดย Field ไหนรูปแบบ ASC, DESC
  • Limit ใช้สำหรับจำกัดจำนวนข้อมูล
  • Start ใช้สำหรับกำหนดจุดเริ่มของชุดข้อมูล ใช้รวมกับ Limit เพื่อทำ Pagination

อ่าาาา จบเถอะยาวเกิ๊น 🤮 เขียนจนเช้าเลย ฝากปรบมือเป็นกำลังใจด้วยนะครับ 😝ขอบคุณที่อ่านมาถึงตรงนี้ ติดตามกันไว้ถ้าสนใจอะไรแบบนี้ มีมาเรื่อยๆแน่นอน ต้องบอกเลยว่าผมก็ค่อนข้างใหม่สำหรับการสร้าง Backend API เลย แต่ Strapi ช่วยนำทางได้เยอะเลย ทุกคนน่าจะเห็นทางแล้วเกท 🤯 นำไปใช้กันได้ ถ้าตรงไหนอธิบายผิดพลาดไป ก็ขออภัยด้วยนะครับ 🙏

ผมคิดว่ามันเป็นอะไรค่อนข้างน่าสนใจ และ อยากรู้ว่าใครที่สนใจ หรือใช้มันอยู่บ้าง ขอเรียนเชิญเข้า Facebook Group ด้วยกันครับ รวมกันเป็น Community เอาไว้ถามปัญหา อัพเดทข้อมูลข่าวสารต่างๆครับ 2 กลุ่มเลย สร้างตะกี้บอกเลย 🤴

👨‍💻 Strapi Thailand 🚀

👩‍💻 Headless CMS Thailand 🗿

--

--