こんにちは、KOUKIです。
GolangのWebフレームワークであるfiberを使ってAPIを開発しています。
前回は、プロダクトの検索機能を実装しました。
今回は、プロダクトのソート機能を実装しましょう。
尚、本記事は「React, NextJS and Golang: A Rapid Guide – Advanced」コースを参考にしています。解釈は私が勝手に付けているので、本物をみたい場合は受講をお勧めします!
<目次>
前回
作るもの
Ambassdor機能を作りたいと思います。エンドポイントは、次の通りです。
- GET /api/ambassador/products/frontend
- GET /api/ambassador/products/backend
- POST /api/ambassador/links
- GET /api/ambassador/stats
- GET /api/ambassador/rankings
今回は、「/api/ambassador/products/backend」への処理を追加します。
ソート機能
プロダクトのソートは、URLの末尾の「sort=?」キーワードで実現しようと思います。前回の検索機能とやり方は同じですね。
「?」に指定するキーワードは、以下に固定します。
- asc ・・・ 昇順
- desc ・・・降順
1 2 3 |
// 例 http://localhost:8000/api/ambassador/products/backend?sort=asc http://localhost:8000/api/ambassador/products/backend?sort=desc |
asc(昇順)ソートの組み込み
前回実装したプロダクト検索処理(ProductBackend関数)に、asc(昇順)ソートを組み込みます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
// productController.go package controllers import ( "admin/src/database" "admin/src/models" "context" "encoding/json" "sort" "strconv" "strings" "time" "github.com/gofiber/fiber/v2" ) ... func ProductBackend(ctx *fiber.Ctx) error { ... // キャッシュ操作 ... // 検索 .... // ソート if sortParam := ctx.Query("sort"); sortParam != "" { sortLower := strings.ToLower(sortParam) if sortLower == "asc" { sort.Slice(searchProducts, func(i, j int) bool { return searchProducts[i].Price < searchProducts[j].Price }) } } return ctx.JSON(searchProducts) } |
ここでは、「Price」の価格が小さい順で商品が並ぶように実装しました。
また、ソートには、sortパッケージのSliceメソッドを使いました。
検証1
以下のパラメーターで検証してみましょう。
- URL: http://localhost:8000/api/ambassador/products/backend?sort=asc
- 形式: GET


Priceが小さい順に並んでいるので、OKですね。
desc(降順)ソートの組み込み
次に、desc(降順)ソートを実装しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// productController.go func ProductBackend(ctx *fiber.Ctx) error { ... // ソート if sortParam := ctx.Query("sort"); sortParam != "" { ... } else if sortLower == "desc" { sort.Slice(searchProducts, func(i, j int) bool { return searchProducts[i].Price > searchProducts[j].Price }) } } return ctx.JSON(searchProducts) } |
今度は、Priceが大きい順に商品が並ぶようにしました。
検証2
以下のパラメーターで検証してみましょう。
- URL: http://localhost:8000/api/ambassador/products/backend?sort=desc
- 形式: GET


今度もOKですね。ちゃんとPriceが大きい順に表示されています。
次回
次回は、ページネーション機能を実装しましょう。
Go言語まとめ
ソースコード
ここまでのソースコードを以下に記載します。
productController.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
// productController.go package controllers import ( "admin/src/database" "admin/src/models" "context" "encoding/json" "sort" "strconv" "strings" "time" "github.com/gofiber/fiber/v2" ) func Products(ctx *fiber.Ctx) error { var products []models.Product // 全てのプロダクトを取得 database.DB.Find(&products) return ctx.JSON(products) } func CreateProducts(ctx *fiber.Ctx) error { var product models.Product // リクエストデータをパースする if err := ctx.BodyParser(&product); err != nil { return err } // プロダクト取得 database.DB.Create(&product) return ctx.JSON(product) } func GetProduct(ctx *fiber.Ctx) error { // リクエストからIDを取得 id, _ := strconv.Atoi(ctx.Params("id")) var product models.Product product.ID = uint(id) // プロダクト検索 database.DB.Find(&product) return ctx.JSON(product) } func UpdateProduct(ctx *fiber.Ctx) error { // リクエストからIDを取得 id, _ := strconv.Atoi(ctx.Params("id")) product := models.Product{} product.ID = uint(id) if err := ctx.BodyParser(&product); err != nil { return err } // プロダクト更新 database.DB.Model(&product).Updates(&product) return ctx.JSON(product) } func DeleteProduct(ctx *fiber.Ctx) error { // リクエストからIDを取得 id, _ := strconv.Atoi(ctx.Params("id")) product := models.Product{} product.ID = uint(id) // プロダクト削除 database.DB.Delete(&product) return nil } func ProductFrontend(ctx *fiber.Ctx) error { var products []models.Product var c = context.Background() redisKey := "products_frontend" expiredTime := 30 * time.Minute // products_frontend keyでRedisからデータを取得 result, err := database.Cache.Get(c, redisKey).Result() if err != nil { database.DB.Find(&products) // Redisにデータを格納するため、エンコードする productBytes, err := json.Marshal(&products) if err != nil { panic(err) } // products_fronend keyでRedisにデータを格納 err = database.Cache.Set(c, redisKey, productBytes, expiredTime).Err() if err != nil { panic(err) } } else { // デコードする json.Unmarshal([]byte(result), &products) } return ctx.JSON(products) } func ProductBackend(ctx *fiber.Ctx) error { var products []models.Product var c = context.Background() redisKey := "products_backend" expiredTime := 30 * time.Minute // キャッシュ操作 result, err := database.Cache.Get(c, redisKey).Result() if err != nil { database.DB.Find(&products) productBytes, err := json.Marshal(&products) if err != nil { panic(err) } database.Cache.Set(c, redisKey, productBytes, expiredTime).Err() } else { json.Unmarshal([]byte(result), &products) } var searchProducts []models.Product // 検索 // urlの?q=XXXXから文字列を取得 if q := ctx.Query("q"); q != "" { // 大文字小文字の区別をなくすため、全て小文字扱いにする lower := strings.ToLower(q) for _, product := range products { // 検索条件1: Title if strings.Contains(strings.ToLower(product.Title), lower) || // 検索条件2: Description strings.Contains(strings.ToLower(product.Description), lower) { searchProducts = append(searchProducts, product) } } } else { // 検索しない場合は、全てのデータを返却 searchProducts = products } // ソート if sortParam := ctx.Query("sort"); sortParam != "" { sortLower := strings.ToLower(sortParam) if sortLower == "asc" { sort.Slice(searchProducts, func(i, j int) bool { return searchProducts[i].Price < searchProducts[j].Price }) } else if sortLower == "desc" { sort.Slice(searchProducts, func(i, j int) bool { return searchProducts[i].Price > searchProducts[j].Price }) } } return ctx.JSON(searchProducts) } |
コメントを残す
コメントを投稿するにはログインしてください。