สร้าง Reactive RESTful Web Service ต่อ PostgreSQL ด้วย R2DBC
หลายคนพัฒนา Reactive RESTful web service ด้วย Spring WebFlux จำเป็นต้องเลือกใช้ NonSQL database เพราะว่ารองรับ Reactive ไม่สามารถใช้งาน Relational Database อย่าง MySQL หรือ PostgreSQL ได้ แต่ตอนนี้ เราสามารถใช้ R2DBC เป็น ตัวเชื่อมระหว่าง Reactive API กับ Relational DB ได้แล้ว ในบทความนี้จะมาลองใช้งาน R2DBC เชื่อมต่อกับ PostgreSQL อย่างง่ายๆ ดูว่าใช้อย่างไร
R2DBC
ย่อมาจาก Reactive Relational Database Connectivity ซึ่งเป็นตัวเชื่อมต่อระหว่าง Reactive Programming APIs และ Relational Database โดยใช้ Reactive Streams spec รองรับ fully-reactive non-blocking API และรองรับ blocking อย่าง JDBC ซึ่งสามารถทำงานได้กับ SQL Database ได้หลากหลาย และทำให้เปลี่ยนจากโมเดล “one thread per connection” ไปเป็นระบบที่สามารถ scale ได้
เมื่อก่อนเป็น Experiment dependency ของ Spring framework อยู่ แต่ตอนนี้ได้พัฒนาเสร็จสมบูรณ์แล้วและ release มาพร้อม Spring Boot 2.3.0
สามารถศึกษาเพิ่มเติมเกี่ยวกับความสามารถของ R2DBC ได้ที่ https://r2dbc.io/
Create Project
สร้าง Spring Boot project ด้วย start.spring.io โดยเลือก dependency เป็น Spring Reactive Web, Spring Data R2DBC, PostgreSQL Driver และ Lombok ซึ่งในบทความนี้สร้างเป็น maven project
- Spring Reactive Web — เป็น Spring WebFlux สำหรับสร้าง RESTful Web Service
- Spring Data R2DBC — เป็นตัว R2DBC สำหรับเชื่อมต่อกับ Relational DB
- PostgreSQL Driver — เป็น PostgreSQL driver ใช้ติดต่อ PostgreSQL server
- Lombok — เป็น library ที่ช่วยให้เราลด boilerplate code ต่างๆ
เมื่อเราใช้ IDE อย่าง IntelliJ หรือ Eclipse ก็แก้ไขใน pom.xml นิดหน่อย โดยลบ scope ของ dependency j2dbc-postgresql
เพราะว่าเราจะต้องใช้บาง class ในนี้สร้าง configuration สำหรับติดต่อกับ PostgreSQL database ให้เหลือแค่นี้
<dependencies>
.....
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-postgresql</artifactId>
</dependency>
.....
</dependencies>
Create PostgreSQL Config
เนื่องจากจะต้องเชื่อมต่อกับ PostgreSQL DB ดังนั้นเราจะต้องสร้าง configuration ที่ระบุข้อมูลต่างๆ เกี่ยวกับการเชื่อมต่อ สามารถทำได้ 2 วิธี คือ config ใน applicaiton config หรือ java configuration
ซึ่งในบทความนี้จะใช้ PostgreSQL ที่ทำงานบนเครื่อง ดังนั้นข้อมูลเชื่อมต่อต่างๆ ดังนี้ โดยที่ port 5432
เป็น default port ของ PostgreSQL และ Username/ Password ก็ตามที่ตั้งค่าไว้
โดย configuration จะสร้าง bean ของ ConnectionFactory
ที่ใช้ PostgresqlConnectionFactory
และ PostgresqlConnectoinConfiguration
builder สร้างข้อมูลการเชื่อมต่อ ซึ่งเป็น class ใน j2dbc-postgresql
แต่จะเป็นต้องสร้าง table customer
ใน database ด้วย SQL statement นี้เสียก่อน หรือไม่ก็บันทึก SQL statement นี้ไว้ในไฟล์ schema.sql
ใน resources
DROP TABLE IF EXISTS customer;
CREATE TABLE customer (id SERIAL PRIMARY KEY, first_name VARCHAR(255), last_name VARCHAR(255));
Create RESTful Web Service
ทีนี้เราก็มาสร้าง RESTful Web Service ด้วย Spring WebFlux ง่ายๆ ซึ่งประกอบด้วย Controller, Service และ Repository รวมทั้ง Customer data model ที่เป็น class data model ง่ายๆ ประกอบด้วย id
, firstName
และ lastName
CustomerController
CustomerService
CustomerRepository
ใน Repository method สามารถใช้ @Query
annotation เช่นเดียวกับการใช้ Spring Data + JDBC และใช้ SQL statement ทั่วไปได้
Run Application
เมื่อสร้างส่วนต่างๆ เสร็จเรียบร้อยก็ลอง run application ด้วยคำสั่ง mvn spring-boot:run
ถ้ารันได้ไม่ error ก็แสดงว่า Web Service เราทำงานได้ในเบื้องต้น
ซึ่งอาจจะทดลองใช้ Postman หรือ command line request ไปที่ endpoint http://localhost:8080/customers
เพื่อดูว่ามี error ไหมและควรจะ return เป็น JSON list เปล่าๆ ถ้ามี error แสดงว่ามีปัญหาจากจากเชื่อมต่อของการกำหนดค่าให้กับ Configuration
Test Web Application
ซึ่งในบทความนี้จะมาเขียน Integration test เพื่อทดสอบ RESTful Web Service ที่ใช้ R2DBC ว่าทำงานได้ตรงที่เราต้องการหรือไม่ โดยใช้ SpringBootTest
และใช้ WebTestClient
เพื่อทดสอบในแต่ละ Test case ของ Controller ที่มีฟังก์ชันของ CRUD operation
สรุป
จากที่ได้ทดลองใช้งาน R2DBC เชื่อมต่อ Relational Database อย่าง PostgreSQL ของ Reactive RESTful Web Service นั้นจะเห็นได้ว่า R2DBC สำหรับ Spring Boot นั้นยังพัฒนาไม่สมบูรณ์เท่าไหร่ เพราะยังไม่รองรับ Query derivation เหมือน Spring Data ตัวอื่นๆ ดังนั้นถ้าจะ query ที่ไม่ใช้ method พื้นฐานก็จำเป็นต้องใช้ @Query มากำหนด SQL query statement เอง แต่โดยรวมแล้วใช้งานได้ดีเลยทีเดียว เหมาะสำหรับคนที่ต้องการใช้ Spring WebFlux กับ Relational DB ที่ legacy system ส่วนใหญ่ใช้กัน