Pair Programming : ระบบบริหารจัดการร้านกาแฟ Online

ให้นักศึกษาพัฒนา REST API สำหรับระบบบริหารจัดการร้านกาแฟ Online อย่างง่าย โดยใช้ Gin Framework

ความต้องการของระบบ

  1. ระบบสามารถแสดงรายการเมนูกาแฟทั้งหมด
  2. ระบบสามารถค้นหาเมนูกาแฟด้วยชื่อหรือประเภท
  3. ระบบสามารถแสดงรายละเอียดของเมนูกาแฟจากรหัสเมนู
  4. ระบบสามารถรับ Order ใหม่และคำนวณเวลาที่คาดว่าจะเสร็จ
  5. ระบบต้องมี Middleware สำหรับบันทึกเวลาการเข้าถึงและ Endpoint ที่ถูกเรียกใช้งาน

โครงสร้างข้อมูล

// เมนูกาแฟ
type Coffee struct {
    ID          string  `json:"id"`
    Name        string  `json:"name"`
    Type        string  `json:"type"` // เช่น "Espresso", "Latte", "Cappuccino"
    Price       float64 `json:"price"`
    Description string  `json:"description"`
}

// ออร์เดอร์
type Order struct {
    OrderID           string    `json:"order_id"`
    CoffeeID          string    `json:"coffee_id"`
    Quantity          int       `json:"quantity"`
    CreatedAt         string    `json:"created_at"`
    EstimatedDelivery string    `json:"estimated_delivery"`
    Status            string    `json:"status"` // "Pending", "In Progress", "Completed"
}

ข้อมูลตัวอย่าง

var coffees = []Coffee{
    {ID: "c001", Name: "Espresso", Type: "Espresso", Price: 60, Description: "เข้มข้น กลมกล่อม"},
    {ID: "c002", Name: "Americano", Type: "Espresso", Price: 65, Description: "เอสเพรสโซ่ผสมน้ำร้อน"},
    {ID: "c003", Name: "Latte", Type: "Latte", Price: 75, Description: "เอสเพรสโซ่ผสมนมร้อน"},
    {ID: "c004", Name: "Cappuccino", Type: "Cappuccino", Price: 75, Description: "เอสเพรสโซ่ผสมนมร้อนและฟองนม"},
    {ID: "c005", Name: "Mocha", Type: "Mocha", Price: 80, Description: "เอสเพรสโซ่ผสมนมร้อนและช็อกโกแลต"},
}

Endpoints ที่ต้องพัฒนา

GET /coffees แสดงรายการเมนูกาแฟทั้งหมด
GET /coffees/:id แสดงรายละเอียดเมนูกาแฟจากรหัส
GET /coffees/search ค้นหาเมนูกาแฟด้วย query parameters (name และ type)
POST /orders สร้าง Order ใหม่ (ใช้เวลาเตรียม 5 นาทีต่อ 1 แก้ว)
GET /orders/:order_id - ดูสถานะของ Order

1. GET /coffees - แสดงรายการเมนูกาแฟทั้งหมด

Request

GET /coffees HTTP/1.1
Host: localhost:8080

Response (HTTP Status 200 OK)

{
  "coffees": [
    {
      "id": "c001",
      "name": "Espresso",
      "type": "Espresso",
      "price": 60,
      "description": "เข้มข้น กลมกล่อม"
    },
    {
      "id": "c002",
      "name": "Americano",
      "type": "Espresso",
      "price": 65,
      "description": "เอสเพรสโซ่ผสมน้ำร้อน"
    },
    {
      "id": "c003",
      "name": "Latte",
      "type": "Latte",
      "price": 75,
      "description": "เอสเพรสโซ่ผสมนมร้อน"
    },
    {
      "id": "c004",
      "name": "Cappuccino",
      "type": "Cappuccino",
      "price": 75,
      "description": "เอสเพรสโซ่ผสมนมร้อนและฟองนม"
    },
    {
      "id": "c005",
      "name": "Mocha",
      "type": "Mocha",
      "price": 80,
      "description": "เอสเพรสโซ่ผสมนมร้อนและช็อกโกแลต"
    }
  ]
}

2. GET /coffees/:id - แสดงรายละเอียดเมนูกาแฟจากรหัส

Request (กรณีปกติ)

GET /coffees/c003 HTTP/1.1
Host: localhost:8080

Response (กรณีปกติ)

{
  "id": "c003",
  "name": "Latte",
  "type": "Latte",
  "price": 75,
  "description": "เอสเพรสโซ่ผสมนมร้อน"
}

Request (กรณีไม่พบ)

GET /coffees/c999 HTTP/1.1
Host: localhost:8080

Response (กรณีไม่พบ)

{
  "error": "Coffee not found"
}

3. GET /coffees/search - ค้นหาเมนูกาแฟด้วย query parameters

Request (ค้นหาด้วยชื่อ)

GET /coffees/search?name=lat HTTP/1.1
Host: localhost:8080

Response (ค้นหาด้วยชื่อ)

{
  "coffees": [
    {
      "id": "c003",
      "name": "Latte",
      "type": "Latte",
      "price": 75,
      "description": "เอสเพรสโซ่ผสมนมร้อน"
    }
  ]
}

Request (ค้นหาด้วยประเภท)

GET /coffees/search?type=Espresso HTTP/1.1
Host: localhost:8080

Response (ค้นหาด้วยประเภท)

{
  "coffees": [
    {
      "id": "c001",
      "name": "Espresso",
      "type": "Espresso",
      "price": 60,
      "description": "เข้มข้น กลมกล่อม"
    },
    {
      "id": "c002",
      "name": "Americano",
      "type": "Espresso",
      "price": 65,
      "description": "เอสเพรสโซ่ผสมน้ำร้อน"
    }
  ]
}

Request (ไม่มีผลลัพธ์)

GET /coffees/search?name=frappe HTTP/1.1
Host: localhost:8080

Response (ไม่มีผลลัพธ์)

{
  "coffees": []
}

4. POST /orders - สร้างออร์เดอร์ใหม่

Request (กรณีปกติ)

POST /orders HTTP/1.1
Host: localhost:8080
Content-Type: application/json

{
  "coffee_id": "c003",
  "quantity": 2
}

Response (กรณีปกติ)

{
  "order_id": "o12345",
  "coffee_id": "c003",
  "quantity": 2,
  "created_at": "2025-03-03T15:30:45+07:00",
  "estimated_delivery": "2025-03-03T15:40:45+07:00",
  "status": "Pending"
}

Request (รหัสกาแฟไม่ถูกต้อง)

POST /orders HTTP/1.1
Host: localhost:8080
Content-Type: application/json

{
  "coffee_id": "c999",
  "quantity": 1
}

Response (รหัสกาแฟไม่ถูกต้อง)

{
  "error": "Coffee not found"
}

Request (จำนวนไม่ถูกต้อง)

POST /orders HTTP/1.1
Host: localhost:8080
Content-Type: application/json

{
  "coffee_id": "c003",
  "quantity": 0
}

Response (จำนวนไม่ถูกต้อง)

{
  "error": "Invalid quantity, must be greater than 0"
}

5. GET /orders/:order_id - ดูสถานะของ Order

Request (กรณีปกติ)

GET /orders/o12345 HTTP/1.1
Host: localhost:8080

Response (กรณีปกติ)

{
  "order_id": "o12345",
  "coffee_id": "c003",
  "quantity": 2,
  "created_at": "2025-03-03T15:30:45+07:00",
  "estimated_delivery": "2025-03-03T15:40:45+07:00",
  "status": "In Progress"
}

Request (กรณีไม่พบออร์เดอร์)

GET /orders/o99999 HTTP/1.1
Host: localhost:8080

Response (กรณีไม่พบออร์เดอร์)

{
  "error": "Order not found"
}

ตัวอย่างโครงสร้าง Middleware

func LoggingMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // บันทึกเวลาเริ่มต้น
        startTime := time.Now()
        
        // บันทึก Endpoint ที่ถูกเรียก
        path := c.Request.URL.Path
        
        // ดำเนินการต่อไปยังส่วนถัดไป (handler หรือ middleware ถัดไป)
        c.Next()
        
        // บันทึกเวลาสิ้นสุดและคำนวณเวลาที่ใช้
        endTime := time.Now()
        latency := endTime.Sub(startTime)
        
        // แสดงข้อมูลการเข้าถึง
        log.Printf("| %s | %s | %v |", c.Request.Method, path, latency)
    }
}

HTTP Status Code ที่ควรใช้

200 OK สำหรับการเรียกดูข้อมูลสำเร็จ
201 Created สำหรับการสร้างข้อมูลใหม่สำเร็จ
400 Bad Request สำหรับข้อมูลที่ส่งมาไม่ถูกต้อง
404 Not Found สำหรับไม่พบข้อมูลที่ร้องขอ
500 Internal Server Error สำหรับข้อผิดพลาดภายในเซิร์ฟเวอร์