#การพัฒนา REST API ด้วย Quarkus: จากเริ่มต้นสู่ CRUD API

Quarkus เป็น Java framework ที่ออกแบบมาสำหรับการพัฒนาแอปพลิเคชันแบบ Cloud Native, Microservices และ Container โดยเฉพาะ สามารถนำมาใช้สร้าง REST API ที่ทำงานร่วมกับ Jakarta REST, Hibernate ORM, PostgreSQL, Docker และ Kubernetes ได้

บทความนี้สาธิตการสร้าง REST API สำหรับจัดการข้อมูลสินค้า โดยใช้แนวคิด CRUD ได้แก่ Create, Read, Update และ Delete

#Architecture

Client / Postman / Frontend
          |
          | HTTP + JSON
          v
+-------------------------+
|      Quarkus REST       |
|     ProductResource     |
+------------+------------+
             |
             v
+-------------------------+
| Hibernate ORM + Panache |
+------------+------------+
             |
             | JDBC
             v
+-------------------------+
|       PostgreSQL        |
+-------------------------+

#เทคโนโลยีที่ใช้

  • Java 17 หรือใหม่กว่า
  • Quarkus
  • Quarkus REST + Jackson
  • Hibernate ORM with Panache
  • PostgreSQL
  • Maven
  • cURL หรือ Postman

#1. ตรวจสอบ Java และ Maven

ตรวจสอบ Java:

java --version

ตรวจสอบ Maven:

mvn --version

สำหรับ Windows สามารถติดตั้ง Eclipse Temurin JDK 17 ผ่าน winget ได้:

winget install EclipseAdoptium.Temurin.17.JDK

หลังติดตั้งให้เปิด Terminal ใหม่แล้วตรวจสอบอีกครั้ง

java --version

#2. สร้าง Quarkus Project

หากติดตั้ง Quarkus CLI แล้ว สามารถสร้างโครงการด้วยคำสั่ง:

quarkus create app com.example:product-api \
  --extension='rest-jackson,hibernate-orm-panache,jdbc-postgresql'

เข้าไปยัง project:

cd product-api

Extension สำคัญประกอบด้วย:


Extension หน้าที่


rest-jackson สร้าง REST endpoint และแปลง Java Object ↔ JSON

hibernate-orm-panache ORM และช่วยลด boilerplate ใน persistence layer

#jdbc-postgresql PostgreSQL JDBC driver

โครงสร้างที่เราจะใช้:

product-api/
├── pom.xml
└── src/
    ├── main/
    │   ├── java/
    │   │   └── com/example/
    │   │       ├── entity/
    │   │       │   └── Product.java
    │   │       └── resource/
    │   │           └── ProductResource.java
    │   └── resources/
    │       └── application.properties
    └── test/

#3. สร้างฐานข้อมูล PostgreSQL

สร้างฐานข้อมูลชื่อ:

productdb

ตัวอย่างด้วย PostgreSQL CLI:

CREATE DATABASE productdb;

จากนั้นกำหนดค่าการเชื่อมต่อในไฟล์:

src/main/resources/application.properties
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=postgres
quarkus.datasource.password=postgres
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/productdb

quarkus.hibernate-orm.schema-management.strategy=update

ในระบบ Production ไม่ควรเก็บ username/password จริงไว้ใน source code ควรใช้ Environment Variables หรือ Secret Management


#4. สร้าง Product Entity

สร้างไฟล์:

src/main/java/com/example/entity/Product.java
package com.example.entity;

import io.quarkus.hibernate.orm.panache.PanacheEntity;
import jakarta.persistence.Entity;

@Entity
public class Product extends PanacheEntity {

    public String name;
    public double price;
}

การสืบทอด PanacheEntity ทำให้ Entity มี id และ utility methods สำหรับจัดการข้อมูล เช่น:

Product.listAll();
Product.findById(id);
product.persist();
product.delete();

จึงเหมาะสำหรับการเริ่มต้นเรียนรู้ Active Record Pattern ด้วย Quarkus


#5. สร้าง REST Resource

สร้างไฟล์:

src/main/java/com/example/resource/ProductResource.java
package com.example.resource;

import com.example.entity.Product;

import jakarta.transaction.Transactional;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;

import java.net.URI;
import java.util.List;

@Path("/api/products")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ProductResource {

    @GET
    public List<Product> getAll() {
        return Product.listAll();
    }

    @GET
    @Path("/{id}")
    public Product getById(@PathParam("id") Long id) {
        Product product = Product.findById(id);

        if (product == null) {
            throw new NotFoundException();
        }

        return product;
    }

    @POST
    @Transactional
    public Response create(Product product) {
        product.persist();

        return Response
                .created(URI.create("/api/products/" + product.id))
                .entity(product)
                .build();
    }

    @PUT
    @Path("/{id}")
    @Transactional
    public Product update(
            @PathParam("id") Long id,
            Product input) {

        Product product = Product.findById(id);

        if (product == null) {
            throw new NotFoundException();
        }

        product.name = input.name;
        product.price = input.price;

        return product;
    }

    @DELETE
    @Path("/{id}")
    @Transactional
    public Response delete(@PathParam("id") Long id) {

        Product product = Product.findById(id);

        if (product == null) {
            throw new NotFoundException();
        }

        product.delete();

        return Response.noContent().build();
    }
}

#6. ทำความเข้าใจ Annotation

#@Path

กำหนด URL ของ Resource:

@Path("/api/products")

ดังนั้น endpoint หลักคือ:

http://localhost:8080/api/products

#@GET

ใช้สำหรับ HTTP GET:

@GET
public List<Product> getAll()

#@POST

ใช้เพิ่มข้อมูล:

@POST
@Transactional
public Response create(Product product)

#@PUT

ใช้แก้ไขข้อมูล:

@PUT
@Path("/{id}")
@Transactional

#@DELETE

ใช้ลบข้อมูล:

@DELETE
@Path("/{id}")
@Transactional

#@Transactional

Operation ที่มีการเปลี่ยนแปลงข้อมูลในฐานข้อมูลควรทำงานภายใน Transaction เช่น POST, PUT และ DELETE


#7. Endpoint ที่ได้

Method Endpoint รายละเอียด


GET /api/products แสดงสินค้าทั้งหมด GET /api/products/{id} ค้นหาสินค้าตาม ID POST /api/products เพิ่มสินค้า PUT /api/products/{id} แก้ไขสินค้า DELETE /api/products/{id} ลบสินค้า


#8. Run Quarkus แบบ Development Mode

macOS / Linux:

./mvnw quarkus:dev

Windows:

.\mvnw.cmd quarkus:dev

Quarkus จะเริ่มทำงานที่:

http://localhost:8080

จุดเด่นของ Development Mode คือรองรับ Live Coding ทำให้แก้ไข source code และทดสอบผลได้อย่างรวดเร็ว


#9. ทดสอบ Create API

ส่ง HTTP POST:

curl -X POST http://localhost:8080/api/products \
  -H "Content-Type: application/json" \
  -d '{
    "name": "MacBook Pro",
    "price": 69900
  }'

ตัวอย่าง Response:

{
  "id": 1,
  "name": "MacBook Pro",
  "price": 69900.0
}

#10. ทดสอบ Read API

อ่านสินค้าทั้งหมด:

curl http://localhost:8080/api/products

ตัวอย่าง:

[
  {
    "id": 1,
    "name": "MacBook Pro",
    "price": 69900.0
  }
]

ค้นหาตาม ID:

curl http://localhost:8080/api/products/1

#11. ทดสอบ Update API

curl -X PUT http://localhost:8080/api/products/1 \
  -H "Content-Type: application/json" \
  -d '{
    "name": "MacBook Pro M5",
    "price": 74900
  }'

#12. ทดสอบ Delete API

curl -X DELETE http://localhost:8080/api/products/1

หากสำเร็จ API จะตอบกลับด้วย HTTP Status:

204 No Content

#13. HTTP Status Code ที่ควรรู้

REST API ควรเลือก HTTP Status Code ให้สอดคล้องกับผลลัพธ์:

Status ความหมาย ตัวอย่าง


200 OK สำเร็จ GET, PUT 201 Created สร้าง resource สำเร็จ POST 204 No Content สำเร็จแต่ไม่มี response body DELETE 400 Bad Request Request ไม่ถูกต้อง Validation 404 Not Found ไม่พบ Resource ID ไม่มีในระบบ 500 Internal Server Error Server Error Exception ที่ไม่ได้จัดการ


#14. Architecture สำหรับระบบจริง

ตัวอย่างก่อนหน้านี้ใช้ Resource ติดต่อกับ Entity โดยตรง เหมาะกับการเรียนรู้และระบบขนาดเล็ก

สำหรับระบบขนาดกลางหรือใหญ่ แนะนำ:

HTTP Request
     |
     v
+------------+
|  Resource  |  REST / HTTP
+-----+------+
      |
      v
+------------+
|  Service   |  Business Logic
+-----+------+
      |
      v
+------------+
| Repository |  Data Access / Panache
+-----+------+
      |
      v
+------------+
| PostgreSQL |
+------------+

โครงสร้าง package:

com.example
├── dto
│   ├── ProductRequest.java
│   └── ProductResponse.java
├── entity
│   └── Product.java
├── repository
│   └── ProductRepository.java
├── resource
│   └── ProductResource.java
├── service
│   └── ProductService.java
└── exception
    └── ...

แนวทางนี้ช่วยแยกความรับผิดชอบของแต่ละ layer และทำให้ระบบทดสอบและบำรุงรักษาได้ง่ายขึ้น


#15. Active Record กับ Repository Pattern

Panache รองรับสองแนวทางหลัก

#Active Record

@Entity
public class Product extends PanacheEntity {
    public String name;
}

ใช้งาน:

Product.listAll();
Product.findById(1L);

เหมาะกับระบบขนาดเล็กหรือการเรียนรู้

#Repository Pattern

@ApplicationScoped
public class ProductRepository
        implements PanacheRepository<Product> {
}

จาก Service สามารถเรียก:

repository.listAll();
repository.findById(id);
repository.persist(product);

Repository Pattern เหมาะเมื่อระบบมี business logic และโครงสร้างหลาย layer มากขึ้น


#16. สิ่งที่ควรเพิ่มก่อนนำไปใช้ Production

CRUD API เป็นเพียงจุดเริ่มต้น ระบบจริงควรเพิ่มองค์ประกอบ เช่น:

  • DTO แยก Request/Response ออกจาก Entity
  • Bean Validation เช่น @NotBlank, @Positive
  • Global Exception Handling
  • Pagination / Filtering / Sorting
  • OpenAPI และ Swagger UI
  • Authentication / Authorization
  • JWT หรือ OpenID Connect
  • Unit Test และ Integration Test
  • Database Migration ด้วย Flyway หรือ Liquibase
  • Environment Variables / Secrets
  • Health Check
  • Logging และ Observability
  • Docker
  • CI/CD
  • Kubernetes

ตัวอย่าง DTO ที่มี Validation:

public class ProductRequest {

    @NotBlank
    public String name;

    @Positive
    public double price;
}

จากนั้น endpoint สามารถใช้:

public Response create(@Valid ProductRequest request)

ช่วยป้องกันข้อมูลไม่ถูกต้องเข้าสู่ business layer


#17. Quarkus กับ Microservices

Quarkus ไม่ได้จำกัดอยู่แค่ CRUD API แต่สามารถใช้เป็น foundation ของ Microservices architecture เช่น:

                 API Gateway
                      |
       +--------------+--------------+
       |              |              |
       v              v              v
+-------------+ +-------------+ +-------------+
| User Service| |Product      | |Order Service|
|   Quarkus   | |Service      | |   Quarkus   |
+-------------+ |Quarkus      | +-------------+
                +-------------+
       |              |              |
       +--------------+--------------+
                      |
               Message Broker

สามารถต่อยอดร่วมกับ PostgreSQL, Kafka, Redis, OpenTelemetry, Prometheus, Docker และ Kubernetes ได้


#สรุป

การสร้าง REST API ด้วย Quarkus มีขั้นตอนหลักดังนี้:

Install Java
     ↓
Create Quarkus Project
     ↓
Add REST + Panache + PostgreSQL
     ↓
Create Entity
     ↓
Create REST Resource
     ↓
Configure Database
     ↓
Run quarkus:dev
     ↓
Test CRUD API
     ↓
Add Validation / DTO / Security / Tests
     ↓
Containerize & Deploy

Quarkus จึงเป็นอีกทางเลือกที่น่าสนใจสำหรับ Java Developer ที่ต้องการพัฒนา REST API, Microservices และ Cloud Native Application โดยยังคงใช้ ecosystem ของ Java/Jakarta และสามารถต่อยอดไปสู่ Container และ Kubernetes ได้โดยตรง

#เอกสารอ้างอิง