☰ Mục lục series
Tài liệu Go tiếng Việt
  1. Bắt đầu (Getting started)
    1. Tổng quan
    2. Tải về và cài đặt
    3. Bắt đầu với Go
    4. Quản lý các bản cài đặt Go
    5. Plugin trình soạn thảo và IDE
  2. Dạo quanh Go (A Tour of Go)
    1. Chào mừng
    2. Package, biến và hàm
    3. Điều khiển luồng
    4. Struct, slice và map
    5. Method và interface
    6. Generics
    7. Xử lý đồng thời
  3. Hướng dẫn (Tutorials)
    1. Danh sách hướng dẫn
    2. Tạo một Go module
    3. Gọi mã của bạn từ một module khác
    4. Trả về và xử lý lỗi
    5. Trả về lời chào ngẫu nhiên
    6. Trả về lời chào cho nhiều người
    7. Thêm một test
    8. Biên dịch và cài đặt ứng dụng
    9. Kết luận
    10. Bắt đầu với workspace nhiều module
    11. Phát triển RESTful API với Go và Gin
    12. Truy cập cơ sở dữ liệu quan hệ
    13. Bắt đầu với generics
    14. Bắt đầu với fuzzing
    15. Làm việc với JSON
    16. Tìm và sửa các dependency có lỗ hổng với govulncheck
    17. Tìm và khắc phục phụ thuộc có lỗ hổng với VS Code Go
    18. Viết ứng dụng web
  4. Viết code Go
    1. Cách viết mã Go
    2. Effective Go
    3. Doc Comment trong Go
  5. Module
    1. Phát triển và publish module
    2. Quản lý phụ thuộc
    3. Tổ chức một module Go
    4. Quản lý mã nguồn của module
    5. Cách đánh số phiên bản module
    6. Quy trình phát hành và đánh phiên bản module
    7. Publish một module
    8. Phát triển một bản cập nhật major version
    9. Tham chiếu tệp go.mod
    10. Ngừng hỗ trợ 'go get' cho việc cài đặt tệp thực thi
  6. Cơ sở dữ liệu (Database)
    1. Truy cập cơ sở dữ liệu quan hệ
    2. Mở một handle cơ sở dữ liệu
    3. Thực thi câu lệnh SQL không trả về dữ liệu
    4. Truy vấn dữ liệu
    5. Dùng prepared statement
    6. Thực thi transaction
    7. Huỷ các thao tác đang chạy
    8. Quản lý kết nối
    9. Tránh rủi ro SQL injection
  7. Chẩn đoán và hiệu năng
    1. Chẩn đoán
    2. Hướng dẫn về Go Garbage Collector
    3. Tối ưu hoá dựa trên profile
    4. Data Race Detector
    5. Gỡ lỗi mã Go bằng GDB
    6. Hỗ trợ coverage profiling cho integration test
  8. Bảo mật (Security)
    1. Tổng quan bảo mật
    2. Thực hành tốt về bảo mật cho lập trình viên Go
    3. Quản lý lỗ hổng trong Go
    4. Cơ sở dữ liệu lỗ hổng của Go
    5. Quét lỗ hổng trong IDE
    6. Chính sách CNA của Go
    7. Go Fuzzing
    8. Chi tiết kỹ thuật của Go Fuzzing
    9. Chính sách bảo mật của Go
    10. Threat Model của Go
    11. Các quyết định về bảo mật của Go
    12. Tuân thủ FIPS 140-3
  9. Công cụ và toolchain
    1. Tài liệu về các lệnh
    2. Về lệnh go
    3. Go Toolchains
    4. Telemetry của Go
    5. Cài đặt Go từ mã nguồn
    6. Cài đặt và sử dụng gccgo
  10. Tham khảo
    1. Câu hỏi thường gặp (FAQ)
    2. Go 1 và tương lai của các chương trình Go
    3. Hướng dẫn chuyển đổi sang encoding/json/v2
    4. Hướng dẫn đóng góp
    5. Đóng góp cho frontend gccgo
  11. Phụ lục
    1. Bảng thuật ngữ
Hướng dẫn (Tutorials)

Hướng dẫn: Phát triển RESTful API với Go và Gin

Bản dịch từ go.dev/doc/tutorial/web-service-gin

Hướng dẫn này giới thiệu những kiến thức căn bản để viết một RESTful web service API bằng Go và Gin Web Framework (Gin).

Bạn sẽ thu được nhiều nhất từ hướng dẫn này nếu đã quen cơ bản với Go và bộ công cụ của nó. Nếu đây là lần đầu bạn tiếp xúc với Go, hãy xem Hướng dẫn: Bắt đầu với Go để có phần giới thiệu nhanh.

Gin đơn giản hoá nhiều công việc lập trình liên quan đến việc xây dựng ứng dụng web, trong đó có web service. Trong hướng dẫn này, bạn sẽ dùng Gin để định tuyến request (yêu cầu từ client), lấy thông tin chi tiết của request, và marshal JSON cho response (phản hồi trả về).

Trong hướng dẫn này, bạn sẽ xây dựng một RESTful API server với hai endpoint (đầu mối truy cập của API). Dự án ví dụ của bạn sẽ là một kho dữ liệu về các đĩa nhạc jazz cổ.

Hướng dẫn gồm các phần sau:

  1. Thiết kế các endpoint của API.
  2. Tạo thư mục cho mã nguồn của bạn.
  3. Tạo dữ liệu.
  4. Viết handler (hàm xử lý request) để trả về tất cả các mục.
  5. Viết handler để thêm một mục mới.
  6. Viết handler để trả về một mục cụ thể.

Lưu ý: Xem thêm các hướng dẫn khác tại Tutorials.

Để thử phần này dưới dạng hướng dẫn tương tác hoàn thành trong Google Cloud Shell, hãy bấm nút bên dưới.

Mở trong Cloud Shell

Điều kiện cần

  • Go. Chúng tôi khuyến nghị dùng phiên bản Go mới nhất để theo hướng dẫn này. Xem hướng dẫn cài đặt tại Installing Go.
  • Một công cụ để soạn mã nguồn. Bất kỳ trình soạn thảo văn bản nào bạn có cũng dùng được.
  • Một cửa sổ dòng lệnh. Go hoạt động tốt với mọi terminal trên Linux và Mac, và với PowerShell hoặc cmd trên Windows.
  • Công cụ curl. Trên Linux và Mac, công cụ này thường đã được cài sẵn. Trên Windows, nó có sẵn từ bản Windows 10 Insider build 17063 trở lên. Với các phiên bản Windows cũ hơn, có thể bạn cần cài đặt nó. Xem thêm tại Tar and Curl Come to Windows.

Thiết kế các endpoint của API

Bạn sẽ xây dựng một API cung cấp quyền truy cập vào một cửa hàng bán đĩa than cổ. Vì vậy bạn cần cung cấp các endpoint để client có thể lấy về và thêm album cho người dùng.

Khi phát triển một API, thông thường bạn bắt đầu bằng việc thiết kế các endpoint. Người dùng API của bạn sẽ thành công hơn nếu các endpoint dễ hiểu.

Dưới đây là các endpoint bạn sẽ tạo trong hướng dẫn này.

/albums

  • GET – Lấy danh sách tất cả album, trả về dưới dạng JSON.
  • POST – Thêm một album mới từ dữ liệu request gửi lên dưới dạng JSON.

/albums/:id

  • GET – Lấy một album theo ID của nó, trả về dữ liệu album dưới dạng JSON.

Tiếp theo, bạn sẽ tạo một thư mục cho mã nguồn của mình.

Tạo thư mục cho mã nguồn của bạn

Để bắt đầu, hãy tạo một dự án cho đoạn mã bạn sắp viết.

  1. Mở cửa sổ dòng lệnh và chuyển về thư mục home của bạn.

    Trên Linux hoặc Mac:

    $ cd

    Trên Windows:

    C:\> cd %HOMEPATH%
  2. Dùng dòng lệnh, tạo một thư mục cho mã nguồn của bạn với tên là web-service-gin.

    $ mkdir web-service-gin
    $ cd web-service-gin
  3. Tạo một module để bạn có thể quản lý các phụ thuộc.

    Chạy câu lệnh go mod init, truyền cho nó đường dẫn của module chứa mã nguồn của bạn.

    $ go mod init example/web-service-gin
    go: creating new go.mod: module example/web-service-gin

    Câu lệnh này tạo ra tệp go.mod, nơi các phụ thuộc bạn thêm vào sẽ được liệt kê để theo dõi. Để biết thêm về việc đặt tên module bằng module path, xem Managing dependencies.

Tiếp theo, bạn sẽ thiết kế các cấu trúc dữ liệu để xử lý dữ liệu.

Tạo dữ liệu

Để mọi thứ đơn giản trong hướng dẫn này, bạn sẽ lưu dữ liệu trong bộ nhớ. Một API điển hình hơn sẽ tương tác với một cơ sở dữ liệu.

Lưu ý rằng lưu dữ liệu trong bộ nhớ nghĩa là tập hợp các album sẽ mất đi mỗi lần bạn dừng server, rồi được tạo lại khi bạn khởi động nó.

Viết mã nguồn

  1. Dùng trình soạn thảo văn bản, tạo một tệp tên là main.go trong thư mục web-service. Bạn sẽ viết mã Go của mình trong tệp này.

  2. Trong main.go, ở đầu tệp, dán vào khai báo package sau đây.

    package main

    Một chương trình độc lập (khác với một thư viện) luôn nằm trong package main.

  3. Bên dưới khai báo package, dán vào khai báo sau của struct album. Bạn sẽ dùng nó để lưu dữ liệu album trong bộ nhớ.

    Các struct tag như json:"artist" chỉ định tên của một trường sẽ là gì khi nội dung của struct được tuần tự hoá thành JSON. Nếu không có chúng, JSON sẽ dùng tên trường viết hoa của struct – một phong cách không phổ biến lắm trong JSON.

    // album represents data about a record album.
    type album struct {
    	ID     string  `json:"id"`
    	Title  string  `json:"title"`
    	Artist string  `json:"artist"`
    	Price  float64 `json:"price"`
    }
  4. Bên dưới khai báo struct bạn vừa thêm, dán vào slice sau gồm các struct album chứa dữ liệu mà bạn sẽ dùng để khởi đầu.

    // albums slice to seed record album data.
    var albums = []album{
    	{ID: "1", Title: "Blue Train", Artist: "John Coltrane", Price: 56.99},
    	{ID: "2", Title: "Jeru", Artist: "Gerry Mulligan", Price: 17.99},
    	{ID: "3", Title: "Sarah Vaughan and Clifford Brown", Artist: "Sarah Vaughan", Price: 39.99},
    }

Tiếp theo, bạn sẽ viết mã để hiện thực endpoint đầu tiên của mình.

Viết handler để trả về tất cả các mục

Khi client gửi request tới GET /albums, bạn muốn trả về tất cả các album dưới dạng JSON.

Để làm điều này, bạn sẽ viết những phần sau:

  • Logic để chuẩn bị một response
  • Mã để ánh xạ đường dẫn của request tới logic của bạn

Lưu ý rằng thứ tự này ngược với thứ tự chúng được thực thi lúc chạy, nhưng bạn đang thêm các phụ thuộc trước, rồi mới tới đoạn mã phụ thuộc vào chúng.

Viết mã nguồn

  1. Bên dưới đoạn mã struct bạn đã thêm ở phần trước, dán vào đoạn mã sau để lấy danh sách album.

    Hàm getAlbums này tạo JSON từ slice các struct album, rồi ghi JSON đó vào response.

    // getAlbums responds with the list of all albums as JSON.
    func getAlbums(c *gin.Context) {
    	c.IndentedJSON(http.StatusOK, albums)
    }

    Trong đoạn mã này, bạn:

    • Viết một hàm getAlbums nhận một tham số gin.Context. Lưu ý rằng bạn có thể đặt cho hàm này bất kỳ tên nào – cả Gin lẫn Go đều không yêu cầu một định dạng tên hàm cụ thể.

      gin.Context là phần quan trọng nhất của Gin. Nó mang theo thông tin chi tiết của request, kiểm tra tính hợp lệ và tuần tự hoá JSON, cùng nhiều việc khác. (Dù tên gọi tương tự, nó khác với package context có sẵn của Go.)

    • Gọi Context.IndentedJSON để tuần tự hoá struct thành JSON và thêm nó vào response.

      Đối số đầu tiên của hàm là HTTP status code mà bạn muốn gửi tới client. Ở đây, bạn truyền hằng số StatusOK từ package net/http để biểu thị 200 OK.

      Lưu ý rằng bạn có thể thay Context.IndentedJSON bằng lời gọi Context.JSON để gửi JSON gọn hơn. Trên thực tế, dạng có thụt lề dễ làm việc hơn nhiều khi gỡ lỗi và khác biệt về kích thước thường là nhỏ.

  2. Gần đầu tệp main.go, ngay bên dưới khai báo slice albums, dán đoạn mã dưới đây để gán hàm handler cho một đường dẫn endpoint.

    Đoạn này thiết lập một liên kết trong đó getAlbums xử lý các request tới đường dẫn endpoint /albums.

    func main() {
    	router := gin.Default()
    	router.GET("/albums", getAlbums)
    
    	router.Run("localhost:8080")
    }

    Trong đoạn mã này, bạn:

    • Khởi tạo một Gin router (bộ định tuyến) bằng Default.

    • Dùng hàm GET để liên kết phương thức HTTP GET và đường dẫn /albums với một hàm handler.

      Lưu ý rằng bạn đang truyền tên của hàm getAlbums. Điều này khác với việc truyền kết quả của hàm, tức là truyền getAlbums() (để ý cặp ngoặc đơn).

    • Dùng hàm Run để gắn router vào một http.Server và khởi động server.

  3. Gần đầu tệp main.go, ngay bên dưới khai báo package, import các package bạn cần để hỗ trợ đoạn mã vừa viết.

    Những dòng mã đầu tiên sẽ trông như thế này:

    package main
    
    import (
    	"net/http"
    
    	"github.com/gin-gonic/gin"
    )
  4. Lưu tệp main.go.

Chạy mã nguồn

  1. Bắt đầu theo dõi module Gin như một phụ thuộc.

    Tại dòng lệnh, dùng go get để thêm module github.com/gin-gonic/gin làm phụ thuộc cho module của bạn. Dùng đối số dấu chấm với nghĩa “lấy các phụ thuộc cho mã nguồn trong thư mục hiện tại.”

    $ go get .
    go get: added github.com/gin-gonic/gin v1.7.2

    Go đã phân giải và tải về phụ thuộc này để thoả mãn khai báo import mà bạn đã thêm ở bước trước.

  2. Từ dòng lệnh trong thư mục chứa main.go, chạy mã nguồn. Dùng đối số dấu chấm với nghĩa “chạy mã nguồn trong thư mục hiện tại.”

    $ go run .

    Khi mã nguồn đang chạy, bạn có một HTTP server đang chạy mà bạn có thể gửi request tới.

  3. Từ một cửa sổ dòng lệnh mới, dùng curl để gửi một request tới web service đang chạy của bạn.

    $ curl http://localhost:8080/albums

    Câu lệnh này sẽ hiển thị dữ liệu mà bạn đã nạp sẵn cho service.

    [
            {
                    "id": "1",
                    "title": "Blue Train",
                    "artist": "John Coltrane",
                    "price": 56.99
            },
            {
                    "id": "2",
                    "title": "Jeru",
                    "artist": "Gerry Mulligan",
                    "price": 17.99
            },
            {
                    "id": "3",
                    "title": "Sarah Vaughan and Clifford Brown",
                    "artist": "Sarah Vaughan",
                    "price": 39.99
            }
    ]

Bạn đã khởi động được một API! Ở phần tiếp theo, bạn sẽ tạo thêm một endpoint với mã xử lý request POST để thêm một mục.

Viết handler để thêm một mục mới

Khi client gửi một request POST tới /albums, bạn muốn thêm album được mô tả trong body của request vào dữ liệu album hiện có.

Để làm điều này, bạn sẽ viết những phần sau:

  • Logic để thêm album mới vào danh sách hiện có.
  • Một chút mã để định tuyến request POST tới logic của bạn.

Viết mã nguồn

  1. Thêm mã để đưa dữ liệu album vào danh sách album.

    Ở đâu đó sau các câu lệnh import, dán vào đoạn mã sau. (Cuối tệp là một vị trí tốt cho đoạn mã này, nhưng Go không bắt buộc thứ tự khai báo các hàm.)

    // postAlbums adds an album from JSON received in the request body.
    func postAlbums(c *gin.Context) {
    	var newAlbum album
    
    	// Call BindJSON to bind the received JSON to
    	// newAlbum.
    	if err := c.BindJSON(&newAlbum); err != nil {
    		return
    	}
    
    	// Add the new album to the slice.
    	albums = append(albums, newAlbum)
    	c.IndentedJSON(http.StatusCreated, newAlbum)
    }

    Trong đoạn mã này, bạn:

    • Dùng Context.BindJSON để binding body của request vào newAlbum.
    • Nối struct album được khởi tạo từ JSON vào slice albums.
    • Thêm status code 201 vào response, cùng với JSON biểu diễn album bạn vừa thêm.
  2. Sửa hàm main của bạn để nó bao gồm hàm router.POST, như sau.

    func main() {
    	router := gin.Default()
    	router.GET("/albums", getAlbums)
    	router.POST("/albums", postAlbums)
    
    	router.Run("localhost:8080")
    }

    Trong đoạn mã này, bạn:

    • Liên kết phương thức POST tại đường dẫn /albums với hàm postAlbums.

      Với Gin, bạn có thể liên kết một handler với một tổ hợp phương thức HTTP và đường dẫn. Bằng cách này, bạn có thể định tuyến riêng các request gửi tới cùng một đường dẫn dựa trên phương thức mà client đang dùng.

Chạy mã nguồn

  1. Nếu server vẫn đang chạy từ phần trước, hãy dừng nó lại.

  2. Từ dòng lệnh trong thư mục chứa main.go, chạy mã nguồn.

    $ go run .
  3. Từ một cửa sổ dòng lệnh khác, dùng curl để gửi một request tới web service đang chạy của bạn.

    $ curl http://localhost:8080/albums \
        --include \
        --header "Content-Type: application/json" \
        --request "POST" \
        --data '{"id": "4","title": "The Modern Sound of Betty Carter","artist": "Betty Carter","price": 49.99}'

    Câu lệnh này sẽ hiển thị các header và JSON của album vừa được thêm.

    HTTP/1.1 201 Created
    Content-Type: application/json; charset=utf-8
    Date: Wed, 02 Jun 2021 00:34:12 GMT
    Content-Length: 116
    
    {
        "id": "4",
        "title": "The Modern Sound of Betty Carter",
        "artist": "Betty Carter",
        "price": 49.99
    }
  4. Như ở phần trước, dùng curl để lấy về danh sách album đầy đủ, nhờ đó bạn có thể xác nhận rằng album mới đã được thêm vào.

    $ curl http://localhost:8080/albums \
        --header "Content-Type: application/json" \
        --request "GET"

    Câu lệnh này sẽ hiển thị danh sách album.

    [
            {
                    "id": "1",
                    "title": "Blue Train",
                    "artist": "John Coltrane",
                    "price": 56.99
            },
            {
                    "id": "2",
                    "title": "Jeru",
                    "artist": "Gerry Mulligan",
                    "price": 17.99
            },
            {
                    "id": "3",
                    "title": "Sarah Vaughan and Clifford Brown",
                    "artist": "Sarah Vaughan",
                    "price": 39.99
            },
            {
                    "id": "4",
                    "title": "The Modern Sound of Betty Carter",
                    "artist": "Betty Carter",
                    "price": 49.99
            }
    ]

Ở phần tiếp theo, bạn sẽ thêm mã để xử lý một request GET cho một mục cụ thể.

Viết handler để trả về một mục cụ thể

Khi client gửi một request tới GET /albums/[id], bạn muốn trả về album có ID khớp với tham số đường dẫn id.

Để làm điều này, bạn sẽ:

  • Thêm logic để lấy về album được yêu cầu.
  • Ánh xạ đường dẫn tới logic đó.

Viết mã nguồn

  1. Bên dưới hàm postAlbums bạn đã thêm ở phần trước, dán đoạn mã sau để lấy về một album cụ thể.

    Hàm getAlbumByID này sẽ trích xuất ID trong đường dẫn của request, rồi tìm album khớp với nó.

    // getAlbumByID locates the album whose ID value matches the id
    // parameter sent by the client, then returns that album as a response.
    func getAlbumByID(c *gin.Context) {
    	id := c.Param("id")
    
    	// Loop over the list of albums, looking for
    	// an album whose ID value matches the parameter.
    	for _, a := range albums {
    		if a.ID == id {
    			c.IndentedJSON(http.StatusOK, a)
    			return
    		}
    	}
    	c.IndentedJSON(http.StatusNotFound, gin.H{"message": "album not found"})
    }

    Trong đoạn mã này, bạn:

    • Dùng Context.Param để lấy tham số đường dẫn id từ URL. Khi ánh xạ handler này tới một đường dẫn, bạn sẽ đặt một placeholder cho tham số đó trong đường dẫn.

    • Lặp qua các struct album trong slice, tìm struct có giá trị trường ID khớp với giá trị tham số id. Nếu tìm thấy, bạn tuần tự hoá struct album đó thành JSON và trả về như một response với mã HTTP 200 OK.

      Như đã nói ở trên, một service thực tế nhiều khả năng sẽ dùng một truy vấn cơ sở dữ liệu để thực hiện việc tra cứu này.

    • Trả về lỗi HTTP 404 bằng http.StatusNotFound nếu không tìm thấy album.

  2. Cuối cùng, sửa hàm main của bạn để nó bao gồm một lời gọi mới tới router.GET, trong đó đường dẫn giờ là /albums/:id, như trong ví dụ sau.

    func main() {
    	router := gin.Default()
    	router.GET("/albums", getAlbums)
    	router.GET("/albums/:id", getAlbumByID)
    	router.POST("/albums", postAlbums)
    
    	router.Run("localhost:8080")
    }

    Trong đoạn mã này, bạn:

    • Liên kết đường dẫn /albums/:id với hàm getAlbumByID. Trong Gin, dấu hai chấm đứng trước một mục trong đường dẫn biểu thị rằng mục đó là một tham số đường dẫn.

Chạy mã nguồn

  1. Nếu server vẫn đang chạy từ phần trước, hãy dừng nó lại.

  2. Từ dòng lệnh trong thư mục chứa main.go, chạy mã nguồn để khởi động server.

    $ go run .
  3. Từ một cửa sổ dòng lệnh khác, dùng curl để gửi một request tới web service đang chạy của bạn.

    $ curl http://localhost:8080/albums/2

    Câu lệnh này sẽ hiển thị JSON của album có ID mà bạn đã dùng. Nếu không tìm thấy album, bạn sẽ nhận được JSON kèm một thông báo lỗi.

    {
            "id": "2",
            "title": "Jeru",
            "artist": "Gerry Mulligan",
            "price": 17.99
    }

Kết luận

Xin chúc mừng! Bạn vừa dùng Go và Gin để viết một RESTful web service đơn giản.

Các chủ đề tiếp theo được gợi ý:

Mã nguồn hoàn chỉnh

Phần này chứa mã nguồn của ứng dụng mà bạn xây dựng với hướng dẫn này.

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

// album represents data about a record album.
type album struct {
	ID     string  `json:"id"`
	Title  string  `json:"title"`
	Artist string  `json:"artist"`
	Price  float64 `json:"price"`
}

// albums slice to seed record album data.
var albums = []album{
	{ID: "1", Title: "Blue Train", Artist: "John Coltrane", Price: 56.99},
	{ID: "2", Title: "Jeru", Artist: "Gerry Mulligan", Price: 17.99},
	{ID: "3", Title: "Sarah Vaughan and Clifford Brown", Artist: "Sarah Vaughan", Price: 39.99},
}

func main() {
	router := gin.Default()
	router.GET("/albums", getAlbums)
	router.GET("/albums/:id", getAlbumByID)
	router.POST("/albums", postAlbums)

	router.Run("localhost:8080")
}

// getAlbums responds with the list of all albums as JSON.
func getAlbums(c *gin.Context) {
	c.IndentedJSON(http.StatusOK, albums)
}

// postAlbums adds an album from JSON received in the request body.
func postAlbums(c *gin.Context) {
	var newAlbum album

	// Call BindJSON to bind the received JSON to
	// newAlbum.
	if err := c.BindJSON(&newAlbum); err != nil {
		return
	}

	// Add the new album to the slice.
	albums = append(albums, newAlbum)
	c.IndentedJSON(http.StatusCreated, newAlbum)
}

// getAlbumByID locates the album whose ID value matches the id
// parameter sent by the client, then returns that album as a response.
func getAlbumByID(c *gin.Context) {
	id := c.Param("id")

	// Loop through the list of albums, looking for
	// an album whose ID value matches the parameter.
	for _, a := range albums {
		if a.ID == id {
			c.IndentedJSON(http.StatusOK, a)
			return
		}
	}
	c.IndentedJSON(http.StatusNotFound, gin.H{"message": "album not found"})
}

Nội dung gốc: Go Documentation © The Go Authors, giấy phép CC BY 3.0. Bản dịch và ghi chú: Lê Văn Dũng.