👋

【1日1zenn - day15】クエリパラメータの付与から取り出しまで

2025/01/06に公開

直近、1日1zennサイズに収まるような何かがあまりなかったので、
一旦小ネタをまとめようかと思います。
とか思ったけど書いてみたら一定のサイズになったからヨシ!

クエリパラメータの作成から取り出しまで

自分はFEをReactとTypeScript、BEをKotlinとSpring Bootで開発してるので、それメインになります。

前提メモ

https://apidog.com/jp/blog/introduction-to-api-parameters/
GETリクエストではクエリパラメータで検索することがメインで、POSTやPUTだとボディパラメータが利用されがち。DELETEはURIパスで指定することが多そう。
ちゃんと構造化されたデータを受け取ったりしたいときはJSON形式にするのが普通だけど、自分の案件では個人情報などとは一切関係ない(セキュリティリスクがない)単一のデータをPOSTする時とかにもパラメータで書いたりしてる。

[FE]クエリパラメータの作成

URL全体を作る場合

https://www.npmjs.com/package/url-join
このパッケージが主要そう。

インストール

npm install url-join

作成するコード例

import urlJoin from 'url-join';

const fullUrl = urlJoin('http://www.google.com', 'a', '/b/cd', '?foo=123');

上記で作成されたURL

http://www.google.com/a/b/cd?foo=123

ソースコードを見ると、
?とかのパラメータ記号がついていたり、すでに/がついている場合は/をつけない処理がありそうですね。
これでURIパスやクエリパラメータを作れそう。

単純にパラメータだけを作る場合

URLSearchParamsを使い、以下みたいにやれそう

const params = new URLSearchParams();
params.append("key", "value");
params.append("page", "1");
params.append("size", "10");

const url = `https://example.com/search?${params.toString()}`;
console.log(url); // https://example.com/search?key=value&page=1&size=10

[BE]クエリパラメータの作成

UriComponentsBuilderを使うのが一般的そう。

UriComponentsBuilderは色々メソッドあるけど、以下を使いそう

  • fromUriString(パラメをつけたいURIの文字列)
    • 元のURIの中で、どこがクエリパラメータでどこがドメインかなどがわかるらしい
    • 既存のクエリを保持したりするために使う
    • '='や'&'みたいな予約語がある場合に正常に動くよう担保したり
  • queryParams(つけたいパラメータ)
    • つけたいパラメータはNullableで MultiValueMap<String,String>を受け取る
    • 値が指定されていない場合はクエリパラメータ名のみが追加される(例: "?foo=bar" ではなく "?foo")とドキュメントに書いてあるけど、なんか動作確認したらnullで受け取った場合にクエリパラメータ名も入らない場合もあったのでよくわからぬ
  • toUriString()
    • URI文字列を作る

以下みたいな感じ

UriComponentsBuilder.fromUriString(パラメをつけたいURIの文字列).queryParams(つけたいパラメータ群).toUriString()

そしてつけたいパラメータはMultiValueMapである必要があるので、以下みたいにパラメータを作る

private fun buildParams(userId: String, isPermit: Boolean): String {
  val params = LinkedMultiValueMap<String, String>()
  params.add("userId", userId)
  params.add("isPermit", isPermit.toString)
  return params
}

これでUriを作るメソッドを以下みたいに準備してる場合は、

private fun buildUriWithParams(baseUri: String, params: MultiValueMap<String, String>): String {
  return UriComponentsBuilder.fromUriString(baseUri)
    .queryParams(params)
    .toUriString()
}

として、buildParamsで以下みたいに呼び出す

private fun buildParams(baseUri: String, userId: String, isPermit: Boolean): String {
  val params = LinkedMultiValueMap<String, String>()
  params.add("userId", userId)
  params.add("isPermit", isPermit.toString)
  return buildUriWithParams(baseUri, params)
}

など。

[FE]クエリパラメータの受取

URLSearchParamsを使い、以下みたいにやれそう

const decodeSearch = decodeURIComponent(location.search)
const urlSearchParams = new URLSearchParams(decodeSearch)
const userId = urlSearchParams.get("userId")
  • まずURLの検索文字列をlocation.searchで取得し、エンコードされている場合はdecodeURIComponentに渡してデコードする
  • URLSearchParamsにデコードしたURLを渡してインスタンスを作る
  • getメソッドにキーの文字列を渡す

[BE]クエリパラメータの受取

以下みたいな感じ

	@PostMapping("/confirm-message")
	fun confirmMessage(
		@RequestParam(required = false) name: String,
		@RequestParam(required = false) message: String,
		model: Model
	): String{
		model.addAttribute("name", name)
		model.addAttribute("message", message)
		return "confirm_message"
	}
  • 上記みたいにするとnameとかmessageとかを受け取れる。
  • @RequestParamというアノテーションでパラメータを作る
    • required = falseで任意項目にでき、defaultValueで入力されなかった場合の値を決められる

おわり

なんか掘れば色々ありそうで、渡し方に困ったらまた調べよう。
明日は、ちょっとフロントで作りたい挙動があるけど体力次第かなぁ。
積み残しの整理もしたい。

Discussion