สร้าง CRUD Microservice ด้วย Spring Boot
ในแนวคิดของการสร้าง Microservice นั้นสามารถใช้ภาษาหรือ framework อะไรก็ได้เพราะว่าแต่ละ service จะเป็นอิสระต่อกัน ในบทความนี้ผมจะสร้าง Microservice ด้วย Java framework อย่าง Spring Boot ที่ทำให้เราสามารถสร้าง Microservice ได้ ง่ายและรวดเร็ว
Microservice ที่จะสร้างนี้จะเป็น RESTful Microservice ที่ไม่เพียงแต่ response อย่างเดียวแต่จะสามารถรองรับ HTTP Method อย่างเช่น POST, GET, PUT และ DELETE โดยใช้ CRUD Method เพื่อทำการ Create, Read, Update และ Delete ข้อมูลในฐานข้อมูลซึ่งจะเป็น MySQL
เป็น Microservice ที่เก็บข้อมูลของ Customer ดังนั้น จะมี endpoint ที่ดำเนินการกับ customers resource ภายใต้ prefix path เป็น /api ดังนี้
- GET /api/customers — เรียกดูรายการ Customer ทั้งหมด
- GET /api/customers/{id} — เรียกดู Customer โดย user id
- GET /api/customers?name=xxxx — เรียกดูรายการ Customer ด้วยการค้นหาด้วย name
- POST /api/customers — สร้าง Customer ใหม่
- PUT /api/customers/{id} — แก้ไข Customer โดย user id
- DELETE /api/customers/{id} — ลบ Customer โดย user id
โดยแบบออกเป็น 3 Layer คือ
- Presentation Layer — เป็นชั้นของ Rest Controller ที่จะร้องขอ/ส่งต่อข้อมูลไปยัง Service layer จะใช้ @RestController annotation
- Service Layer — เป็นชั้นที่มี Business Logic เพื่อให้ข้อมูลกับ Presentation Layer และร้องขอข้อมูลจาก Persistence layer จะใช้ @Service annotation
- Persistence Layer — เป็นชั้นที่ติดต่อกับ Database โดยตรงและให้ข้อมูลกับ Service layer จะใช้ extend จากคราส CurdRepository
สร้าง Spring Boot Project
สามารถทำได้หลายวิธี แต่วิธีที่ง่ายที่สุดคือใช้ Spring Initializr ในเว็บโดยไปที่ start.spring.io ซึ่งเป็นเครื่องมือสร้าง Project เริ่มต้นให้เรา โดยใส่ข้อมูลและเลือกว่าจะใช้ dependency อะไรบ้าง แล้ว Generate Project เพียงเท่านี้เราก็ได้ Spring Boot project แล้ว ก็สามารถเลือกได้ว่าจะเป็น Maven หรือ Gradle project ใช้ภาษา Java หรือ Kotlin ก็ได้ แต่ในบทความนี้จะใช้ Maven project และเลือก dependency เป็น Web, JPA, Actuator, MySQL และ Lombok ดังนี้
หลังจากนั้นก็ IDE อย่างเช่น IntelliJ เปิด project ที่ได้จาก Spring Initializr ก็จะได้ โครง project ว่างๆ พร้อมเพิ่มเติมความสามารถ
สร้าง Database
ก่อนที่จะสร้าง application ของ Microservice เราจะต้องสร้าง Database ก่อน ซึ่งในเครื่องของเราจะต้องติดตั้ง MySQL แล้วหรือถ้ายังไม่ติดตั้งก็สามารถ download ทาติดตั้งได้เลย
หลังจากนั้นก็ใช้ terminal/command line สำหรับ macOS ใช้คำสั่ง
$ sudo mysql --password
สร้าง database db_webservice และ user webservice เพื่อใช้เก็บข้อมูลของ User
mysql> create database db_webservice;
mysql> create user 'webservice'@'localhost' identified by 'P@ssw0rd'
mysql> grant all on db_webservice.* to 'webservice'@'localhost';
สร้าง Application Config
เมื่อเรามีฐานข้อมูลแล้วก็มาสร้าง application config ให้สามารถติดต่อกับฐานข้อมูลได้ ซึ่ง Spring Boot รองรับทั้งแบบ properties และแบบ yaml ซึ่งในที่นี้จะใช้ yaml ดังนั้นสร้างไฟล์ application.yml
ขึ้นมา ดังนี้
src/main/resources/application.yml
ตั้งค่าให้กับ server เข้าถึงด้วย port 8080 (เป็นค่าตั้งต้นอยู่แล้วอาจจะไม่ต้องตั้งค่าก็ได้แต่สามารถเปลี่ยนเป็น port อื่นได้) ด้วย server.port
เป็น 8080
และตั้งค่า perfix path ของ endpoint ด้วย server.servlet.contextPath
เป็น /api
ซึ่ง spring.jpa.hibernate.dll-auto
สามารถตั้งค่าได้หลายแบบ เช่น none
, update
, create
, create-drop
ก็จะอ้างอิงถึงการตั้งค่าของ Hibernate ดังนี้
none
— เป็นค่าเริ่มต้นของ MySQL ที่ไม่มีการเปลี่ยนแปลงฐานข้อมูลupdate
— Hibernate จะเปลี่ยนโครงสร้างฐานข้อมูลให้ตรงกับ Entitycreate
— จะสร้างฐานข้อมูลใหม่ทุกครั้ง แต่จะไม่ drop เมื่อปิดการเชื่อมต่อcreate-drop
— จะสร้างฐานข้อมูลและ drop ทุกครั้งเมื่อSessionFactory
ปิด
ที่เลือกใช้ create
เพราะว่าเราไม่มีโครงสร้างฐานข้อมูลดังนั้นเมื่อรันครั้งแรกจะสร้างฐานข้อมูล และสามารถเปลี่ยนเป็น none
หรือ update
ได้ในภายหลัง
ตั้งค่าสำหรับความปลอดภัยของแต่ละ endpoint แบบ Basic Auth ด้วย username และ password ด้วย security.user.name
และ security.user.password
สร้าง Customer Model
ก่อนที่เราจะสร้าง controller เรามาสร้าง Customer Model โดยใช้ @Entity annotation เพื่อกำหนดโครงสร้างของข้อมูล Customer โดยใช้ Lombok มาช่วยเพื่อลด POJO โค้ดพวก getter/setter ไป ด้วย @Data โดยสร้างคลาส Customer
ดังนี้
src/main/java/com/example/demo/customer/Customer.java
โดยกำหนดให้แต่ละ field ของ Customer entity ในตาราง customer มีลักษณะดังนี้
- id — ตัวแปรค่า id ของตาราง customer ซึ่งเป็นค่าที่เพิ่มขึ้นอัตโนมัติ
- firstName — ตัวแปร String ที่จะต้องมีค่า และมีขนาด 2–100 ตัวอักษร
- lastName — ตัวแปร String ที่จะต้องมีค่า และมีขนาด 2–100 ตัวอักษร
- age —ตัวแปร Integer ที่จะต้องมีค่า และมีค่ามากกว่า 18
- email — ตัวแปร String ที่จะต้องมีรูปแบบเป็น email
ซึ่งจะมี validate error message
ของแต่ละตัวแปร นั้นหมายความว่าถ้าไม่ตรงตามที่กำหนดไว้จะ return error message และ status code 400 — Bad Request
สร้าง Customer Controller
สร้าง Controller ของชั้น Presentation ตามที่เราออกแบบไว้ ด้วยการเพิ่มไฟล์ Java class ชื่อ DemoController เข้าไปใน package com.example.demo และใส่ @RestController annotation ที่คลาสและเพิ่ม endpoint ต่างๆ ด้วยการ mapping กับ method ดังนี้
src/main/java/com/example/demo/customer/CustomerController.java
แต่ละ method จะเรียกไปยัง method ของ Service layer และบาง method ตรวจสอบ return value เพื่อ return HTTP response code ที่แตกต่างกันไป
- getCustomers — เรียกข้อมูลรายการของ Customer ทั้งหมด, ซึ่งจะ return code 200 — OK แต่ถ้าไม่มี Customer อยู่ใน DB จะ return array ว่าง
- getCustomer (id) — เรียกข้อมูลของ Customer ด้วย Customer ID, ซึ่งถ้ามี Customer จะ return code 200 — OK, แต่ถ้าไม่มีจะ return code 204 — No Content
- getCustomer (name) — ค้นหา Customer โดยชื่อของ Customer, ซึ่งจะ return code 200 — OK แต่ถ้าไม่มี Customer อยู่ใน DB จะ return array ว่าง
- postCustomer —สร้าง Customer เข้าไปใน DB, ถ้าสร้างสำเร็จจะ return code 201 — Created แต่ถ้าไม่สำเร็จจะ return code 404 —Not Found
- putCustomer — แก้ไขข้อมูลของ Customer ด้วย Customer ID, ถ้าแก้ไขสำเร็จจะ return code 200 — OK แต่ถ้าไม่สำเร็จจะ return code 404 — Not Found
- deleteCustomer — ลบข้อมูลของ Customer ด้วย Customer ID, ถ้าลบสำเร็จจะ return code 200 — OK แต่ถ้าไม่สำเร็จจะ return code 404 — Not Found
สร้าง Customer Service
เนื่องจากตามที่ออกแบบไว้ Controller ซึ่งเป็น Presentation layer จะรับ request จาก User และเรียกผ่าน Service layer เพื่อดำเนินการกับ Database ใน Persistent layer ดังนั้นสร้างคลาส CustomerService ใช้ @Service annotation ดังนี้
src/main/java/com/example/demo/customer/CustomerService.java
โดยที่จะ @Autowired คลาส CustomerRepository จาก Persistence layer เข้ามาใน constructor ของคลาส และเรียกใช้ method ต่างๆ ของ Repository
- retrieveCustomer — ค้นหาข้อมูลของ Customer ทั้งหมด ใน Repository
- retrieveCustomer(Id) — ค้นหาข้อมูลของ Customer ด้วย Id ใน Repository
- retrieveCustomer(name) — ค้นหาข้อมูลของ Customer ด้วยชื่อใน Repository
- createCustomer(Customer) — สร้างข้อมูล Customer ด้วยข้อมูลที่ส่งมาเข้าไปใน Repository โดยที่ลบ Id ของข้อมูลที่ส่งเข้ามาก่อน
- updateCustomer(Id, Customer) — แก้ไขข้อมูลของ Customer ด้วย Id และข้อมูลที่ส่งมาใน Repository โดยลบ Id ของข้อมูลที่ส่งเข้ามาก่อนและตรวจสอบก่อนว่ามีข้อมูลของ Customer นั้นอยู่หรือไม่
- deleteCustomer(Id) — ลบข้อมูลของ Customer ด้วย Id ใน Repository โดย response เป็น boolean ถ้าไม่มีข้อมูลของ Customer อยู่ก็ response เป็น False
สร้าง Repository
เมื่อสร้าง Customer Service แล้ว จะต้องมี Persistence layer หรือส่วนที่ติดต่อกับ database ด้วย Hibernate framework ซึ่งเป็น ORM (Object-Relation Mapping) ที่จะทำหน้าที่เกี่ยวกับ database operation ทั้งหมด โดยสร้าง CustomerRepository
ที่ขยายจาก CrudRepository interface ซึ่งมีความสามารถจัดการ CRUD operation ทั้งหมด และจะเพิ่ม method findByFirstName
ในการค้นหาจากชื่อของ Customer โดยจะต้องให้เป็น Naming convention
src/main/java/com/example/demo/customer/CustomerRepository.java
ซึ่งเราใช้ method ของ Repository ดังนี้ ใน Customer Service (Service layer)
- findAll — ค้นหา Customer ทั้งหมด ที่อยู่ใน DB — Read
- findById — ค้นหา Customer ด้วย Id — Read
- findByFirstName — ค้นหา Customer ด้วย firstName — Read
- save — บันทึก Customer ลง DB — Create/Update
- existById — ตรวจสอบว่ามี Customer ด้วย Id นี้อยู่หรือไม่
- deleteById — ลบ Customer ด้วย Id — Delete
ตั้งค่า Security
ใน Microservice จะมีเรื่องความปลอดภัยของแต่ละ endpoint ดังนั้นการตั้งค่าความปลอดถัยจึงเป็นส่วนที่สำครับ แต่สำหรับบทความนี้จะใช้ Basic Authorization ในการป้องกัน Microservice จากที่เราได้ตั้งค่า Security ไปแล้ว ใน Configuration แต่เราจะต้องตั้งค่า Secure Configuration โดยสร้างคลาส SecureConfig
โดยขยายความสามารถของ WebSecurityConfigureAdapter และ override method configure และใช้ @EnableWebSecurity และ @EnableAutoConfiguration annotation เพื่อเปิดการใช้งาน Web Security และ Config อัตโนมัติ ดังนี้
src/main/java/com/example/demo/config/SecureConfig.java
ทดลองรัน Microservice
หลังจากที่ implement ทั้งหมดแล้วก็ลองรัน Microservice ด้วย IntelliJ หรือจะใช้ คำสั่ง $ mvn spring-boot:run
โดยใช้ Postman เรียกไปยัง endpoint http://localhost:8080/api/customers
ซึ่งจำเป็นต้องเลือก Authorization แบบ Basic Auth
และใส่ Username และ Password ด้วย
ซึ่งเราสามารถลองเรียกทุก endpoint ตามที่เราได้ออกแบบไว้ตั้งแต่ตอนต้นเพื่อดูว่า Microservice ทำงานได้ตามที่ออกแบบไว้หรือไม่
สามารถอ้างอิงโค้ดได้จาก GitHub repo
สรุป
จากขั้นตอนที่กล่าวไปแล้วนั้น ทำให้เราสามาถสร้าง Microservice ด้วย Spring Boot ได้ โดยเป็นตัวอย่างของ resource Customers ที่สามารถดำเนินการด้วย CRUD ได้ ซึ่งรับ HTTP method ด้วย Customer Controller ส่งต่อไปยัง Customer Service เพื่อใช้ Customer Repository เพื่อดำเนินการกับฐานข้อมูล และส่งกลับมายัง User พร้อมด้วย HTTP status ต่างๆ และป้องกัน endpoint ด้วย Basic Authorization แต่การทดสอบสามารถเขียน Test เป็น Unit Test และ Integration Test ซึ่งบทความนี้ไม่ได้ครอบคลุม