最初に
フロントからの特定のリソースに対して検索リクエストが飛んでくる。
そのリクエストはechoで動くサーバがさばく。
検索クエリはstrapi REST API(ここでは以下strapi API)のようになっていることが要件で
汎用性 <【優先度】< ビジネスロジックとのマッチ とすることが条件となっている。
そうした場合、こうやって組みましたの一例を紹介する。
リクエスト内容を分解する
strapi APIでは、ある規格化されたリクエストパラメータを送ることで
柔軟な検索リクエストを受けることができる。
パラメータ参考;Parameters | Strapi Documentation
その処理を模すには、まず処理できる形にリクエストを分解しなければいけない。
その内容について、書いていく。
controller
リクエストを受け取った後、parameters構造体に当てはまるよう分解するメソッドに渡す
import (
search "app/api/request"
"github.com/labstack/echo/v4"
)
func (hc *ProposalSampleController) Index(c echo.Context) error {
queryParams := c.QueryParams()
parameters := search.NewParameters(queryParams)
app/api/request
NewParametersメソッド内でリクエストを分解する
func NewParameters(queryParams url.Values) Parameters {
// sort: 各章で記載
// field: 各章で記載
// pagination: 各章で記載
// filter: 各章で記載
return Parameters{
}
}
パラメータの構造体を定義しておく
type Parameters struct {
Sort search_param.Sort
Filter search_param.Filter
Populate string
Fields search_param.Fields
Pagination search_param.Pagination
}
Sort
並び替え情報
例: ?sort[0]=title:desc
構造体定義
var Asc = "asc"
var Desc = "desc"
type SortParam struct {
TargetTable string
Target string
Sorting string
}
type Sort struct {
SortParam
}
分解の処理
func NewParameters(queryParams url.Values) Parameters {
// sort
var sort search_param.Sort
// 2重でソート条件をつけることはないのでsort[0]のみ対応する
sortQueryParam := queryParams.Get("sort[0]")
if sortQueryParam != "" {
sortQueryParamArray := strings.Split(sortQueryParam, ":")
sort.Target = sortQueryParamArray[0]
if sortQueryParamArray[1] == search_param.Asc {
sort.Sorting = search_param.Asc
}
if sortQueryParamArray[1] == search_param.Desc {
sort.Sorting = search_param.Desc
}
}
// ジョイン先の値でソートする場合は, 別で定義する
// 例としてsizeのデータでソートを指定
// ?sort[size]=xxx:asc
sortSizeQueryParam := queryParams.Get("sort[size]")
if sortSizeQueryParam != "" {
sortSizeQueryParamArray := strings.Split(sortSizeQueryParam, ":")
sort.TargetTable = "resource_size"
sort.Target = sortSizeQueryParamArray[0]
if sortSizeQueryParamArray[1] == search_param.Asc {
sort.Sorting = search_param.Asc
}
if sortSizeQueryParamArray[1] == search_param.Desc {
sort.Sorting = search_param.Desc
}
}
}
Filter
絞り込み
例 filters[field][operator]=value
構造体
type FilterParam struct {
Query []string
Val string
}
type Filter []FilterParam
分解の処理
func NewParameters(queryParams url.Values) Parameters {
// filter
var filter search_param.Filter
for k := range queryParams { // 変数kにはmap(連想配列)のkeyが入る
// filterのクエリのみ処理する
r := regexp.MustCompile(`filter`)
if !r.MatchString(k) {
continue
}
val := queryParams.Get(k)
// [field][operator] の部分を取得
r2 := regexp.MustCompile(`\[(.*?)]`)
getPram := r2.FindAllStringSubmatch(k, -1)
var query []string
for i := 0; i < len(getPram); i++ {
query = append(query, getPram[i][1])
}
filter = append(filter, search_param.FilterParam{
Query: query, // [field, operator] のような値が入っている
Val: val,
})
}
// ~~~略~~~
}
Populate
付加情報
例 ?populate=* / ?populate=Tag
引数1個想定なので、そのままパラメータ取得値を構造体に当てる
func NewParameters(queryParams url.Values) Parameters {
return Parameters{
Populate: queryParams.Get("populate"),
}
}
Fields
表示項目
例 ?fields[0]=title&fields[1]=body
構造体
type Fields []string
分解の処理
func NewParameters(queryParams url.Values) Parameters {
// field
var field search_param.Fields
// 配列のキー番号が連番になっている前提
for i := 0; ; i++ {
key := fmt.Sprintf("fields[%d]", i)
value := queryParams.Get(key)
if len(value) == 0 {
break
}
field = append(field, value)
}
// 省略
}
Pagination
ページネーション
例: ?pagination[page]=1&pagination[pageSize]=10&pagination[withCount]=true
構造体
type Pagination struct {
Page int
PageSize int
WithCount bool
}
分解の処理
func NewParameters(queryParams url.Values) Parameters {
// pagination
var pagination search_param.Pagination
page := queryParams.Get("pagination[page]")
pagination.Page, _ = strconv.Atoi(page)
pageSize := queryParams.Get("pagination[pageSize]")
pagination.PageSize, _ = strconv.Atoi(pageSize)
withCount := queryParams.Get("pagination[withCount]")
if withCount == "true" {
pagination.WithCount = true
} else {
pagination.WithCount = false
}
// 略
}
まとめ
strapiのような検索リクエストをGoで定義した構造体に当てていく処理を紹介した。
また、この検索リクエストParameters構造体を使ったクエリの組み立て部分は別記事で紹介したい。
弊社では、一緒に働いてくれるエンジニアを募集しています。
↓興味のある方はこちらから↓
Wantedly - スタジオアンビルト株式会社
こんなWebサービスを作っています。
・マドリー
・Studio Unbuilt