0
0
Lập trình
Admin Team
Admin Teamtechmely

Xây Dựng API với Query Parameters trong Go

Đăng vào 7 tháng trước

• 6 phút đọc

Xây Dựng API với Query Parameters trong Go

Trong chương trước, chúng ta đã xây dựng một hệ thống định tuyến động có thể xử lý các tham số URL như /users/:id. Tuy nhiên, các API thực tế cần nhiều hơn thế - chúng cần xử lý các tham số truy vấn để lọc dữ liệu, phân trang và nhận đầu vào từ người dùng.

Hôm nay, chúng ta sẽ tìm hiểu cách làm việc với các tham số truy vấn để xây dựng các API tương tác hơn.

Những gì chúng ta đã xây dựng cho đến nay

Từ những chương trước:

  • ✅ Định tuyến động với tham số URL (/users/:id)
  • ✅ Trích xuất và truy cập tham số
  • ✅ Phản hồi JSON cơ bản
  • ❌ Xử lý tham số truy vấn (?name=John&age=25)
  • ❌ Xác thực tham số và chuyển đổi kiểu dữ liệu

Hiểu về Tham số Truy vấn

Khi các lập trình viên frontend thực hiện các yêu cầu như sau:

Copy
// Tìm kiếm với tham số truy vấn
fetch('/search?q=javascript&page=2')

// Chào mừng với tên tùy chọn
fetch('/greet?name=John')

// Các phép toán toán học với tham số
fetch('/math/add?a=10&b=20')

Máy chủ cần trích xuất và sử dụng các tham số truy vấn đó. Khác với tham số URL (:id), tham số truy vấn xuất hiện sau dấu ? và được truyền dưới dạng cặp khóa-giá trị.

Trích xuất Tham số Truy vấn Cơ bản

Bắt đầu với một bộ xử lý chào mừng sử dụng tham số truy vấn. Cập nhật tệp main.go:

go Copy
package main

import (
    "fmt"
    "net/http"
)

func main() {
    server := NewServer(":3000")
    setupRoutes(server)

    server.Start()
}

func setupRoutes(s *Server) {
    s.Router.GET("/greet", greet)
}

func greet(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/plain; charset=utf-8")

    name := r.URL.Query().Get("name")

    if name == "" {
        w.Write([]byte("Xin chào người lạ!"))
        return
    }

    w.Write([]byte(fmt.Sprintf("Xin chào %s", name)))
}

Cách Truy cập Tham số Truy vấn:

  • r.URL.Query() trả về tất cả các tham số truy vấn dưới dạng kiểu url.Values
  • Get("name") trích xuất giá trị cho tham số name
  • Nếu tham số không tồn tại, Get() sẽ trả về chuỗi rỗng

Kiểm tra bộ xử lý này:

Copy
go run .
Copy
curl "http://localhost:3000/greet"
# Trả về: Xin chào người lạ!

curl "http://localhost:3000/greet?name=John"
# Trả về: Xin chào John

curl "http://localhost:3000/greet?name=Jane%20Doe"
# Trả về: Xin chào Jane Doe

Lưu ý cách mã hóa URL hoạt động - %20 trở thành một khoảng trắng.

Nhiều Tham số Truy vấn

Các API thực tế thường cần nhiều tham số. Hãy tạo một bộ xử lý tìm kiếm:

go Copy
func setupRoutes(s *Server) {
    s.Router.GET("/greet", greet)
    s.Router.GET("/search", search)
}

func search(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/plain; charset=utf-8")

    query := r.URL.Query().Get("q")
    page := r.URL.Query().Get("page")

    w.Write([]byte(fmt.Sprintf("Kết quả tìm kiếm cho '%s' (trang %s)", query, page)))
}

Kiểm tra với nhiều tham số:

Copy
curl "http://localhost:3000/search?q=golang"
# Trả về: Kết quả tìm kiếm cho 'golang' (trang )

curl "http://localhost:3000/search?q=golang&page=3"
# Trả về: Kết quả tìm kiếm cho 'golang' (trang 3)

curl "http://localhost:3000/search?page=2&q=web%20development"
# Trả về: Kết quả tìm kiếm cho 'web development' (trang 2)

Thông tin Chính:

  • Thứ tự tham số trong URL không quan trọng
  • Tham số thiếu sẽ trả về chuỗi rỗng
  • Tham số rỗng hiển thị dưới dạng trắng trong đầu ra

Chuyển đổi Kiểu Tham số

Thường thì bạn cần chuyển đổi các tham số truy vấn sang các kiểu cụ thể và xác thực chúng. Hãy tạo một bộ xử lý toán học:

go Copy
func setupRoutes(s *Server) {
    s.Router.GET("/greet", greet)
    s.Router.GET("/search", search)
    s.Router.GET("/math/add", add)
}

func add(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/plain; charset=utf-8")

    a, _ := strconv.ParseInt(r.URL.Query().Get("a"), 0, 0)
    b, _ := strconv.ParseInt(r.URL.Query().Get("b"), 0, 0)

    w.Write([]byte(fmt.Sprintf("%d + %d = %d", a, b, a+b)))
}

Kiểm tra bộ xử lý toán học với các đầu vào khác nhau:

Copy
curl "http://localhost:3000/math/add?a=10&b=20"
# Trả về: 10 + 20 = 30

curl "http://localhost:3000/math/add?a=100&b=-50"
# Trả về: 100 + -50 = 50

curl "http://localhost:3000/math/add?a=hello&b=20"
# Trả về: 0 + 20 = 20

curl "http://localhost:3000/math/add?a=10"
# Trả về: 10 + 0 = 10

Hiểu về Các Kiểu Tham số Khác nhau

Hãy phân tích các cách khác nhau mà khách hàng có thể gửi dữ liệu tới API của bạn:

1. Tham số URL (Tham số Đường dẫn)

Copy
/users/123        → :id = "123"
/api/v1/users/456 → :version = "v1", :id = "456"
  • Phần của đường dẫn URL
  • Bắt buộc (URL sẽ không khớp nếu thiếu)
  • Trích xuất bằng hàm GetPathValue()

2. Tham số Truy vấn

Copy
/search?q=golang&page=2 → q = "golang", page = "2"
  • Sau dấu ? trong URL
  • Tùy chọn (URL vẫn khớp nếu thiếu)
  • Trích xuất bằng r.URL.Query().Get()

3. Sử dụng Kết hợp

Copy
/users/123/posts?limit=10&sort=date
  • :id từ đường dẫn = "123"
  • limit từ truy vấn = "10"
  • sort từ truy vấn = "date"

Các Mô Hình Tham số Truy vấn Thông dụng

Mô Hình 1: Tham số Tùy chọn với Giá trị Mặc định

go Copy
func listUsers(w http.ResponseWriter, r *http.Request) {
    // Lấy tham số với giá trị mặc định
    limitStr := r.URL.Query().Get("limit")
    if limitStr == "" {
        limitStr = "10" // Giá trị mặc định
    }

    sortBy := r.URL.Query().Get("sort")
    if sortBy == "" {
        sortBy = "name" // Sắp xếp mặc định
    }

    // Sử dụng các tham số...
}

Mô Hình 2: Tham số Boolean

go Copy
func listProducts(w http.ResponseWriter, r *http.Request) {
    // Tham số boolean
    inStock := r.URL.Query().Get("in_stock") == "true"
    onSale := r.URL.Query().Get("on_sale") == "true"

    // Sử dụng cờ boolean...
}

Mô Hình 3: Nhiều Giá trị cho cùng một Tham số

go Copy
func filterData(w http.ResponseWriter, r *http.Request) {
    // Lấy tất cả giá trị cho một tham số
    tags := r.URL.Query()["tags"] // []string
    categories := r.URL.Query()["category"] // []string

    // Xử lý nhiều giá trị...
}

Kiểm tra URL: /filter?tags=web&tags=api&category=tutorial&category=golang

So sánh Cách Tiếp cận của Chúng Ta với Các Framework

Cách Tiếp cận của Chúng Ta:

go Copy
func handler(w http.ResponseWriter, r *http.Request) {
    name := r.URL.Query().Get("name")
    id := GetPathValue(r, "id")
}

Framework Gin:

go Copy
func handler(c *gin.Context) {
    name := c.Query("name")
    id := c.Param("id")
}

Framework Echo:

go Copy
func handler(c echo.Context) error {
    name := c.QueryParam("name")
    id := c.Param("id")
}

Các khái niệm là giống nhau - các framework chỉ cung cấp các phương thức tiện lợi!

Triển Khai Hiện Tại

Các bộ xử lý của chúng ta thể hiện việc xử lý tham số truy vấn cơ bản với các mẫu khác nhau:

  • Trích xuất tham số đơn giản bằng r.URL.Query().Get()
  • Xử lý nhiều tham số trong một bộ xử lý
  • Chuyển đổi kiểu sử dụng strconv.ParseInt()

Kiểm Tra Tất Cả Các Bộ Xử Lý

Hãy kiểm tra bộ sưu tập bộ xử lý hoàn chỉnh của chúng ta:

Copy
# Kiểm tra bộ xử lý chào mừng
curl "http://localhost:3000/greet?name=Alice"

# Kiểm tra bộ xử lý tìm kiếm
curl "http://localhost:3000/search?q=golang%20tutorial&page=1"

# Kiểm tra bộ xử lý toán học
curl "http://localhost:3000/math/add?a=15&b=25"

# Kiểm tra với các số không hợp lệ (chúng trở thành 0)
curl "http://localhost:3000/math/add?a=not_a_number&b=10"

Những gì chúng ta đã đạt được

Chúng ta đã có:

  • Trích xuất tham số truy vấn (r.URL.Query().Get())
  • Xử lý nhiều tham số (tìm kiếm với tham số truy vấn + trang)
  • Chuyển đổi kiểu (chuỗi thành số nguyên với strconv.ParseInt())
  • Các phép toán cơ bản với tham số URL

Điều gì tiếp theo?

Trong chương 6, chúng ta sẽ mở rộng khả năng của máy chủ:

  • Lưu trữ Dữ liệu: Làm việc với lưu trữ dữ liệu có cấu trúc
  • API JSON: Tạo xử lý yêu cầu/phản hồi JSON đúng cách
  • Xử lý Thân yêu cầu: Xử lý yêu cầu POST/PUT với dữ liệu JSON
  • Hoạt động CRUD: Xây dựng một API hoàn chỉnh để quản lý tài nguyên

Thử thách: Hãy thử tạo một điểm cuối /calculator mà chấp nhận các tham số operation (cộng, trừ, nhân, chia), a, và b. Xử lý chia cho số 0 và các phép toán không hợp lệ!

Thưởng thêm: Thêm hỗ trợ cho nhiều giá trị: /tags?name=web&name=api&name=tutorial và trả về tất cả các tên thẻ.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào