สร้าง Reactive RESTful Web Service ด้วย Spring WebFlux
ใน Spring 5.0 เป็นต้นมาได้นำเสนอการพัฒนา Web Service ด้วย Reactive Web Stack ด้วย Spring WebFlux ที่ทำให้นักพัฒนาสมารถพัฒนา application ที่เป็นแบบ non-blocking I/O ได้ โดยที่ Spring Framework ได้ใช้ Reactive Stream ที่เป็นมาตรฐานสำหรับ asynchronous stream processing ซึ่งน่าสนใจมาก ในบทความนี้จึงจะนำเสนอการใช้งาน Spring WebFlux ร่วมกับ MongoDB
Spring WebFlux
เมื่อก่อน Web Framework ที่อยู่ใน Spring Framework, Spring Web MVC ทำเพื่อ Servlet API และ Servlet containers แต่ Reactive-Stack web framework อย่างเช่น Spring WebFlux เพิ่มเข้ามาใน Spring version 5.0 เป็น non-blocking I/O ที่รองรับ Reactive Streams และทำงานบน server รุ่นใหม่ อย่างเช่น Netty, Undertow และ Servlet 3.1+ container
Non-blocking web stack จะจัดการกับ concurrency ด้วย thread จำนวนน้อย และ scale ได้โดยใช้ทรัพยากร hardware ไม่มาก ตั้งแต่ Servlet 3.1 มี API สำหรับ Non-blocking I/O แต่อย่างไรก็ตามท้ายที่สุดก็ใช้ Servlet API แบบเดิมที่ synchronous (Filter
, Servlet
) หรือ blocking (getParameter
, getPart
) ทำให้เกิด common API ใหม่ขึ้นมาเพื่อรองรับ non-blocking ที่แท้จริง ในขณะ runtime อย่างเช่น Netty ทำให้เกิด async และ non-blocking ขึ้นมา และใช้งาน functional programming
Programming Models
ใน Spring WebFlux มีตัวเลือกให้เราสามารถเขียนโปรแรมได้ 2 แบบ
- Annotated Controllers: สอดคล้องกับ Spring MVC และรูปแบบ annotation เหมือนกัน ทั้ง Spring MVC และ WebFlux controller รองรับ reactive (Reactor และ RxJava) return type แต่ WebFlux รองรับ reactive
@RequestBody
ด้วย - Functional Endpoint: ใช้รูปแบบ Lamda-based, lightweight และ functional programming เราสามารถงาน utility ที่ application สามารถใช้ route และ handle request สิ่งที่แตกต่างมากกับ annotated controller ก็คือ application เป็นส่วนที่รับผิดชอบจัดการ request จากเริ่มต้นจนจบ เที่ยบกับการประกาศสิ่งที่ต้องการผ่าน annotation และเริ่มใช้งานที่ called back
Create Spring project
สร้าง Spring project ด้วย Spring Initializr ซึ่งในบทความนี้จะใช้ MongoDB มาเป็นส่วน Persistence Layer ดังนั้นเลือก dependency ดังนี้
Reactive Web
— สำหรับ Spring WebFlux และ Netty เพื่อใช้งาน Web ReactiveReactive MongoDB
— สำหรับใช้งาน MongoDB แบบ reactive Spring DataEmbedded MongoDb
— สำหรับใช้งาน MongoDB ใน app โดยที่ไม่ต้องติดตั้งLombok
— เป็นผู้ช่วยเราสร้าง boilerplate code ทำให้เราเขียนโปรแกรมได้เร็วขึ้น
และในบทความนี้จะทำเป็น Gradle project
ด้วย Java
และ Spring Boot 2.1.2
แต่เราจะต้องเปลี่ยน Embedded Mongo
จาก testImplementation
ที่ใช้ตอน Unit Test มาเป็น implementation
เพื่อมาใช้ตอนรันโปรแกรม
Create Model (POJO)
สร้าง model (คลาส Customer) เพื่อเป็นข้อมูลของสำหรับ application โดยใช้ @Data
สำหรับให้สร้าง getter/setter และ @Document
เพื่อกำหนดให้เป็น persist data สำหรับ MongoDB และ @Id เพื่อกำหนดค่าของ field id
อัตโนมัติ
Create Persistence
สร้าง คลาส CustomerRepository
เพื่อเป็น Persistence Layer สำหรับติดต่อกับ MongoDB โดย extend ReactiveCrudRepository
ซึ่งเป็น Repository ที่รองรับ Reactive ใช้งาน CRUD operation และเพิ่ม method findByFirstName
เพื่อ query ด้วย field FirstName
Create Service
สร้าง คลาส CustomerService
เพื่อเป็น Service Layer สำหรับบริการให้ Controller โดยที่ใช้งาน CustomerRepository
ในการเชื่อมต่อกับ MongoDB
ซึ่งจะเห็นได้ว่า method จะ return เป็น Flux
หรือ Mono
ซึ่งเป็น Reactive Stream Publisher
- Flux — เก็บลำดับข้อมูล 0..N (N element) ใช้กับ
getCustomers
ซึ่ง return ข้อมูลมากว่า 1 element - Mono — เก็บลำดับข้อมูล 0..1 (1 element) ใช้กับ method อื่นๆ ที่ return ข้อมูลเพียง element เดียว
Create Controller
สร้างคลาส CustomerController
ซึ่งเป็นส่วนของ Presentation Layer ที่รับข้อมูลจาก User และเรียกใช้บริการจาก CustomerService
จะเห็นได้ว่า method ของ RestController จะ return เป็น Flux
หรือ Mono
เช่นเดียวกับ Service ที่เป็น Reactive และใน postCustomer
และ updateCustomer
รับข้อมูล POST
/PUT
@RequestBody
เป็นแบบ Reactive ด้วย Mono
และเรียกใช้งาน CustomerService
ในแบบ functional programming
Test <UnitTest>
ทดสอบ Reactive RESTful Web Service ที่สร้างขึ้นด้วย Unit Test เพื่อทดสอบในแต่ล่ะ endpoint ของ Controller ด้วย WebTestClient
ซึ่งเป็น reactive client ที่เหมาะสำหรับทดสอบ Reactive Web Service ภายในเป็น WebClient
สามารถดู completed implementation ได้ที่นี่ครับ
สรุป
จากการที่สร้าง Reactive RESTful Web Service ด้วย Spring WebFlux ขึ้นมานี้ จะเห็นได้ว่าแนวคิดการสร้าง Service นั้นแตกต่างจากการใช้ Spring MVC เป็นอย่างมากเพราะว่า method response เป็นแบบ Reactive ใช้ functional programming ในการดำเนินการกับตัวแปรทั้งหมด เพราะว่า return ของ Reactive Spring Data ก็เป็น Reactive ทั้งหมด ดังนั้นจะต้องเรียนรู้ Reactive Java มาก่อนถึงจะใช้งาน Spring WebFlux ด้วย Reactive อย่างราบรื่น