Spring Boot with RESTful Web Services 1/3

Phai Panda
Tech INNO
Published in
5 min readJul 3, 2019

RESTful Web Services หลายท่านเล่า หลายท่านเขียน เราจึงอยากเขียนของเราบ้าง การให้บริการที่เป็นมากกว่าเว็บไซต์ธรรมดา การให้บริการ resources ผ่าน HTTP

ก่อนที่จะไปถึงเรื่องนั้น ผมขอพูดในส่วนของเพื่อนใหม่ เป็นคนใหม่ที่เพิ่งเข้ามารู้จักหน้านี้สักเล็กน้อย (นิดเดียวจริงๆ)

เรามีเน็ต เราต้องการข้อมูลบางอย่างแต่มันไม่ได้อยู่ตรงหน้าเรา เราจึงต้องค้นหาหรือระบุอย่างเจาะจงไปว่าเราต้องการอะไร รอคอยและได้รับผลลัพธ์ในที่สุด

  • เราในที่นี้ให้เรียกว่า Client
  • ข้อมูลบางอย่างให้เรียกว่า Resource
  • ความต้องการให้เรียกเป็น Request
  • ผลลัพธ์ให้เรียกเป็น Response
  • แหล่งที่เก็บข้อมูลนั่นเรียกว่า Server

การเสาะหาประดา Resource ทำบนเส้นทางของ Internet ที่เรียกว่า Protocol* ซึ่งมีหลายประเภท ที่เป็นพื้นฐานมีชื่อว่า HTTP*

กระบวนการเสาะหา Resource ในแต่ละครั้งแสดงเป็นรูปภาพได้ดังนี้

http://ravindranaik.com
  1. Client ส่งคำขอเป็น HTTP Request ไปที่ Server ผ่านระบบ Internet
  2. โปรแกรมที่เรียกว่า Web Server ที่อยู่ ณ ​Server ได้รับ Request นี้ จากนั้น
  3. Server ได้รันโปรแกรมที่รับผิดชอบเพื่อประมวลผล Request นี้
  4. Server จึงส่งกลับค่าผลลัพธ์ที่ได้จากการประมวลผลเรียกว่า HTTP Response กลับไปยัง Client
  5. ท้ายสุด Client ได้รับ Response นั้น

หากยกตัวอย่างให้เน้นไปที่ Resources ว่าเป็นอะไรได้บ้าง ก็คงจะประมาณนี้

  • ต้องการ (request) หน้า HTML แล้ว Server ก็ส่ง (response) HTML ไฟล์นั้นให้
  • ต้องการ (request) style sheet (CSS ไฟล์) แล้ว Server ก็ส่ง (response) CSS ไฟล์นั้นให้
  • ต้องการรูปภาพสกุล JPG แล้ว Server ก็ส่ง JPG ไฟล์นั้นให้
  • ต้องการโค้ด JavaScript แล้ว Server ก็ส่ง JS ไฟล์นั้นให้
  • ต้องการข้อมูลบางอย่าง แล้ว Server ก็ส่งข้อมูลนั้นให้ (อาจอยู่ในรูป XML หรือ JSON) เป็นต้น

เป็นอันว่าผมได้ทักทายเพื่อนใหม่เรียบร้อย ตอนนี้ถ้าจะให้เข้าเรื่อง Spring Boot with RESTful Web Services เลยก็ได้ แต่ผมขอลีลาอีกหน่อย คืออยากเข้าใจสิ่งที่ตนกำลังจะประกาศบอกชาวบ้าน (ซึ่งก็มีโค้ดตัวอย่างเต็มไปหมดในเน็ต) ขอเริ่ม ณ หนทางที่ว่าด้วย REST vs RESTful สองคำนี้ความหมายต่างกัน ไล่เรียงกันเลยครับ

REST

REST ย่อมาจาก REpresentational State Transfer คือความคิดรูปแบบสถาปัตยกรรมซอฟต์แวร์ เพื่อตอบเรื่อง Distributed Hypermedia Systems ง่ายๆว่าใช้ Link เป็นตัวเข้าถึงข้อมูล ไม่ว่าจะเป็น Text ธรรมดา, รูปภาพ, เสียงและอื่นๆ

การสร้างระบบให้เป็น REST ต้องปฏิบัติตามหลักการ 6 ข้อต่อไปนี้ (รวม optional)

  1. Client–server
  2. Stateless
  3. Cacheable
  4. Uniform interface
  5. Layered system
  6. Code on demand (optional)

ที่มา

พูดให้ง่าย REST เป็นวิธีการให้ ผู้ใช้ (Client) ใช้ Link เข้าถึง Resource (Text ธรรมดา, รูปภาพ, เสียงและอื่นๆ) ที่อยู่ ณ เซิร์ฟเวอร์ (Server) ใดๆ

ขยายความกันนิดหน่อย

  • Client ที่ว่าหมายถึง ผู้ใช้ นี่ไม่ใช่คนอย่างเดียวนะ จะเป็นระบบหรือเครื่องคอมพิวเตอร์อื่นก็ได้ เราเรียกต้นทางที่อยากได้ Resource นี้โดยเหมารวมว่า Client
  • Resources แปลว่าทรัพยากร เป็นได้ทุกสิ่งอย่าง ไม่ว่าจะเป็น ตัวหนังสือตัวเดียว, ไฟล์เอกสาร HTML, ไฟล์ CSS, รูปภาพนางสาวไทย, YourTube วีดีโอ, ประวัติการชมภาพยนตร์รูปแบบ JSON เป็นต้น บางคนยากจะเข้าใจคำว่า Resources จะบอกว่าเป็น Data ก็ตามใจ แต่ให้รับทราบร่วมกันว่า Resources นี้ถูกเก็บไว้ ณ ปลายทางที่เรียกด้วยคำกว้างๆว่า Server
  • Link ก็คือลิงก์ เหมือนลิงก์บนหน้าเว็บนี่แหละครับ เพียงแต่เมื่อกดไปแล้วจะได้ Resource กลับมา
  • การใช้เว็บ (ใช้ Link) เพื่อขอหรือเข้าถึง Resource ที่อยู่อีกแหล่งหนึ่ง โดยที่แหล่งดังกล่าวได้สร้างระบบที่สามารถให้บริการ Resources ได้ เราเรียกระบบอย่างนี้ว่า Web Services

RESTful

RESTful คือคำเรียกระบบ Web Services ที่นำนิยาม REST มาใช้ จบ (ผมจำกัดความเท่านี้แหละ)

ดูและฟังเพิ่มเติม

โดยสรุปคือ

  • ระบบที่ให้บริการ Resources ผ่านระบบเครือข่ายเว็บเรียกว่า Web Services
  • RESTful ก็คือการปฏิบัติที่เกิดขึ้นจริงจากนิยามที่เรียกว่า REST
  • RESTful มิได้เน้นการขนส่ง Resource ในรูปแบบเฉพาะ JSON เท่านั้น จะเป็น XML ก็ได้ ทว่าด้วยเรื่องของขนาดและความง่ายของการอ่าน เลือกเป็นแบบ JSON จะดีกว่า
  • Server หรือปลายทางที่ส่ง Resource เป็นผลลัพธ์จะเรียกว่า Endpoint

คำศัพท์เยอะไม่ต้องเครียดไป มันเป็นเสน่ห์ของสายการพัฒนา ให้ฟังจากวีดีโอ อ่านจากเว็บไซต์ หนังสือ ประชุมสัมมนา เรียนรู้จากที่ทำงานหรือถามจากอาจารย์แบบค่อยเป็นค่อยไปนะครับ

ทีนี้มาพูดถึงวิธีการใช้งาน RESTful Web Services กันดีกว่า (สร้างอย่างไร เดี๋ยวสอนด้วย Spring Boot)

วิธีการใช้งาน RESTful Web Services เขาเรียกกันว่า RESTful APIs โดยคำว่า API ย่อมาจาก Application Program Interface คือวิธีการใช้งานสิ่งที่ถูกสร้างขึ้นแล้วนั้น

ถ้าผมให้ RESTful Web Services เป็นหม้อหุงข้าวฉันใด, RESTful APIs ก็คือคู่มือ (ที่แถมมาในกล่อง) การใช้งานหม้อหุงข้าวใบนั้นแหละฉันนั้น (เปิดฝา ใส่น้ำมากน้อย ทำความสะอาดอย่างไร บลาๆๆ)

ดูหน่อยว่า APIs ดังกล่าวเขามีหลักการออกแบบกันอย่างไร

ผมขออ้างอิงจาก REST Resource Naming Guide ของ restfulapi.net ข้างต้น เขาว่า

  • A resource can be a singleton or a collection หมายความว่า ให้ผลลัพธ์เพียงชิ้นเดียว (singleton) หรือให้ผลลัพธ์หลายชิ้น (collection)
    สมมติอยากได้รายการรายละเอียดลูกค้าทั้งหมด ก็ว่า
    /customers
    และถ้าอยากได้รายละเอียดของลูกค้าแค่คนเดียวก็ว่า
    /customers/{customerId}
  • A resource may contain sub-collection resources หมายความว่า collection หลายชิ้นนั้นมี sub-collection แบบหลายชิ้นได้
    ต่อเนื่องจากตัวอย่างก่อนหน้านี้ สมมติอยากได้รายการรายละเอียดของบัญชีทั้งหมดของลูกค้าคนนั้น
    /customers/{customerId}/accounts
    และถ้าอยากได้รายละเอียดของบัญชีเหล่านั้นแค่บัญชีเดียวก็ว่า
    /customers/{customerId}/accounts/{accountId}

ลิงก์หรือเส้นทางการเข้าถึง Resources นี้เรียกว่า URI ย่อมาจาก Uniform Resource Identifier คำว่า identifier นี้ก็คือ ID ใช้อ้างอิงไปยัง Resource ที่ต้องการแบบเจาะจงได้เลย วู้~

อ่านเพิ่มเติม URI

ไหนๆก็มาทาง REST Resource Naming Guide ของ restfulapi.net แล้ว ก็ควรไปต่อให้จบ มา!

REST Resource Naming Best Practices

เขาบอกให้ใช้ คำนาม (noun) มาตั้งเป็นชื่อ Resource (ไม่ควรใช้คำกริยา (verb) เพราะกริยาไม่มี properties)

ตัวอย่างต่อไปนี้แสดงให้เห็นว่าระบบประกอบไปด้วย ผู้ใช้งานระบบ (Users of System), บัญชีผู้ใช้ (User Accounts) และ Network Devices

http://api.example.com/device-management/managed-deviceshttp://api.example.com/device-management/managed-devices/{device-id}http://api.example.com/user-management/usershttp://api.example.com/user-management/users/{user-id}http://api.example.com/user-management/users/{user-id}/accounts

Resource Archetypes

แบ่งออกได้ 4 รูปแบบ ได้แก่

  1. Document
  2. Collection
  3. Store
  4. Controller

จะใช้อย่างหนึ่งอย่างใดหรือผสมรูปแบบก็ได้

Document Archetype

ห้วใจคือใช้ singular name เข้าถึงตัว resource, ให้นึกถึงเอกสารที่เป็นลักษณะของลิงก์แปะบนหน้าเว็บครับ คือกันเลย คือปลายทางเป็นหัวข้อหรือหัวข้อย่อยที่มีลิงก์สื่อไปถึงหัวข้ออื่นๆต่อไปอีก

https://docs.oracle.com/en/database/19.1https://docs.oracle.com/en/database/12.2/cncpthttps://docs.oracle.com/en/database/12.1/cncpt/introduction

Collection Archetype

หัวใจคือ server-managed directory of resources กับ plural name กล่าวคือ resources ถูกแบ่งออกเป็นกลุ่มที่ Server, กระบวนการสร้าง resources ก็อยู่ที่ Server

เราเรียกกลุ่มของ resources ว่า collection ดังนั้น Client อาจเพิ่ม แก้ไข ลบหรือขอ resources ที่ collection ได้ โดยกระบวนการเหล่านี้ขึ้นอยู่กับเงื่อนไขของ collection ว่าจะดำเนินการอย่างไร

ตรงนี้ผมคิดขำๆว่าถ้าให้ collection คือคดีที่ตำรวจรับไว้แล้ว เราซึ่งเป็นผู้เสียหายต้องการไปแจ้งความ (เพิ่มคดี) กับตำรวจ ก็สุดแล้วแต่จ่าท่านจะกรุณาด้วยวิธีการใด

http://api.example.com/device-management/managed-deviceshttp://api.example.com/user-management/usershttp://api.example.com/user-management/users/{id}/accounts

Store Archetype

หัวใจคือ client-managed resource repository กับ plural name กล่าวคือ resource ใดๆนั้นจะถูกเพิ่ม แก้ไขหรือลบโดย Client ได้ด้วยตัวเอง ข้อสังเกตคือเมื่อมี resource ใหม่เกิดขึ้น archetype นี้จะไม่สร้าง URI ขึ้นมาใหม่ ตรงข้ามมันจะใช้ URI เดิมที่ได้มาตั้งแต่แรกเริ่มนั่นต่อยอดต่อไป ตัวอย่างเช่น ต้องการเพิ่ม resource ที่ชื่อ phai เข้าไปใน store นี้จึงได้ว่า

PUT /users/1234/it/phai

เพิ่มรายการสั่งซื้อ (ในรถเข็นช้อปปิ้ง) แก่ user หรือเพิ่มรายการเพลงที่ user เพิ่งเลือก

http://api.example.com/cart-management/users/{id}/cartshttp://api.example.com/song-management/users/{id}/playlists

Controller Archetype

หัวใจของรูปแบบนี้คือ procedural concept กับ verb ที่เป็นอย่างนี้ก็เพราะมีประสงค์จะทำงาน (execute) บางอย่าง อาจมีการส่ง parameters และท้ายที่สุดก็ได้ผลลัพธ์กลับไป สังเกตว่าชื่อของ controller นี้มักจะอยู่ในส่วนท้ายของ URI

POST /alerts/245743/resendhttp://api.example.com/cart-management/users/{id}/cart/checkouthttp://api.example.com/song-management/users/{id}/playlist/play

จะเลือกหรือผสม archetype ไหนก็แล้วแต่ความเหมาะสมของงานนะครับ

ถัดไปเป็นเรื่องการประดิษฐ์ URIs

Consistency คือ key

key ตรงนี้ก็คือการออกแบบให้ API ใช้งานง่าย มี 2 ประเด็น

  1. ลดความคลุมเคลือ
  2. เพิ่มความง่ายในการอ่าน

เพื่อจะตอบประเด็นทั้งสองนี้ เรามาดูว่าเขาแนะนำอย่างไรนะ

1.ใช้เครื่องหมาย forward slash (/) เพื่อแสดงชั้นของความสัมพันธ์ระหว่าง resource

http://api.example.com/device-managementhttp://api.example.com/device-management/managed-deviceshttp://api.example.com/device-management/managed-devices/{id}http://api.example.com/device-management/managed-devices/{id}/scriptshttp://api.example.com/device-management/managed-devices/{id}/scripts/{id}

2.ไม่ใส่ forward slash (/) ไว้ท้าย URI เช่น (ไม่เอานะแบบนี้)

http://api.example.com/device-management/managed-devices/

3.ใช้เครื่องหมาย hyphens ( - ) คั่นกลางระหว่างคำ

http://api.example.com/inventory-management/managed-entities/{id}/install-script-location

4.จากข้อสาม ดังนั้นไม่ควรใช้เครื่องหมาย underscores ( _ )

5.ใช้อักษรภาษาอังกฤษพิมพ์เล็กเสมอ (เล็กบ้างใหญ่บ้างไม่เอา น่าเกลียด)

http://api.example.org/my-folder/my-doc

6.ไม่ใช้ file extensions หรือก็คือใส่สกุลน่ะไม่เอา (ไม่เอานะแบบนี้)

http://api.example.com/device-management/managed-devices.xml

6–1.เพื่อง่ายต่อการ debugging อาจสร้าง API ให้รองรับการถามเป็น query parameters ว่าปลายทางที่กำลังจะคุยด้วยสามารถเข้าใจ media type ลักษณะที่ต้องการนี้ได้หรือไม่ โดยใช้คำว่า accept ได้ไหม

GET http://api.example.com/device-management?accept=application/xml

7.บอกไปเลยว่าเส้นทางนี้คือ API โดยสร้างเป็น subdomain

http://api.phai-panda.org

7–1.และสำหรับชุด API ที่พัฒนาอยู่หรือสำหรับกลุ่มพัฒนา (developer portal)

http://developer.phai-panda.org

CRUD in URIs

CRUD ย่อมาจาก Create Read Update Delete กล่าวคือควรออกแบบ API ให้สามารถจัดการด้วย HTTP request methods

//Get all devices
HTTP GET http://api.example.com/device-management/managed-devices
//Create new Device
HTTP POST http://api.example.com/device-management/managed-devices
//Get device for given Id
HTTP GET http://api.example.com/device-management/managed-devices/{id}
//Update device for given Id
HTTP PUT http://api.example.com/device-management/managed-devices/{id}
//Delete device for given Id
HTTP DELETE http://api.example.com/device-management/managed-devices/{id}

Use query component to filter URI collection

บ่อยครั้งที่เราต้องการคัดกรอง จัดเรียงและหรือต้องการจำกัดปริมาณของ resources จาก collection, แนวทางนี้ให้ผ่าน parameters เข้าท้าย URI เรียกว่า query parameters

http://api.example.com/device-management/managed-deviceshttp://api.example.com/device-management/managed-devices?region=USAhttp://api.example.com/device-management/managed-devices?region=USA&brand=XYZhttp://api.example.com/device-management/managed-devices?region=USA&brand=XYZ&sort=installation-date

Hypermedia as the engine of application state (HATEOAS)

หัวใจคือการนำเสนอความสัมพันธ์กันของ resource ต่างๆผ่าน link เมื่อเรียกไปยัง URI ใดๆ ตัวอย่างเช่น Github APIs

https://api.github.com

ผลลัพธ์

ดูผ่าน JSON Viewer Google Chrome Plugin

บทความนี่ยาวเหลือเกิน (อ่านก็เยอะ) กินพลังมากจริงๆจึงขอแบ่งออกเป็นหลาย parts ส่วนของทฤษฎีทั่วไปมีเท่านี้ ที่เหลือจะว่าด้วย Spring Boot ต่อไป ขอบคุณที่เข้ามาอ่านนะครับ

อ่านต่อ part 2

อ้างอิง

Protocol* นี้คือวิธีการสื่อสารกันระหว่างจุดสองจุด (ความคิดในการประดิษฐ์วิธีการสื่อสาร) มีหลายประเภท ในที่นี้ให้รู้จักแค่ HTTP พอแล้ว

HTTP* มาจาก HyperText Transfer Protocol เป็น protocol พื้นฐานของเครือข่าย WWW (World Wide Web) ว่าด้วยวิธีการเคลื่อนย้ายข้อมูลระหว่าง Client กับ Server

รายละเอียด

--

--