0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

echoでstrapi REST APIのようなパラメータを受ける

Posted at

最初に

フロントからの特定のリソースに対して検索リクエストが飛んでくる。
そのリクエストは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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?