🌀

React: Axios (v1.0.0~)のGETパラメータに配列プロパティを持つオブジェクトを指定する

2022/11/14に公開

AxiosのGETパラメータに配列プロパティを持つオブジェクトを指定すると、
標準では arr[]=1&arr[]=2 といったパラメータクエリーに展開されます。

arr[]=1&arr[]=2 という形式ではサーバー側でパラメータを受け取れない為、arr=1&arr=2といったURLにパースする必要がありました。

axios v1.0.0以前は、クエリー文字列をパースする方法としてqsモジュールを使用する方法が採られていましたが、axios v1.0.0以降から配列のパースに対応したので qsモジュールは不要になりました。
この方法について日本語の情報が見つからなかったので記事にしておきます。

axiosのバージョン: 1.1.2

まずは、arr[]=1&arr[]=2 といった形式でURLに展開されるパターンの、get の簡単なサンプルです。

import axios, { AxiosInstance} from 'axios'

export const axiosClient: AxiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 5000,
  headers: {
    'Content-Type': 'application/json'
  }
})

type SearchFilter = {
  arr: number[]
}

type SearchResult = {
  name: number
  age: number
}

export const search = async (filter: SearchFilter): Promise<SearchResult> => {
  const response = await axiosClient.get<SearchResult>(`/search`, {params:filter})
  return response.data
}

export const sample = async () => {
  const result =  await search({arr: [1, 3, 5, 7]})
  console.log(result)
}

以下の行で何も指定しないと、filterオブジェクトの arrプロパティの配列は、arr[]=1&arr[]=2といったURLに展開されます。

const response = await axiosClient.get<SearchResult>(`/search`, {params:filter})

arr=1&arr=2といったURLにパースするには、AxiosRequestConfig の paramsSerializerプロパティに SerializerOptions indexes: nullを指定します。
paramSerializerは、クエリパラメーターをシリアル化するためプロパティです。

const response = await axiosClient.get<SearchResult>(`/search`, 
    {params:filter,  paramsSerializer: { indexes: null }})

SerializerOptionsの
indexes = true を指定すると arr[0]=1&arr[1]=2といった添え字付きのURLに展開されます。
indexes = false を指定すると arr[]=1&arr[]=2といった添え字なしでブラケットだけのURLに展開されます。これがデフォルトの動作になります。
indexes = nullを指定するとarr=1&arr=2といったURLに展開されます。

getのたびに指定するのは面倒なので、デフォルトコンフィグに指定しまえばいいと思います。

export const axiosClient: AxiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 5000,
  headers: {
    'Content-Type': 'application/json'
  },
  paramsSerializer: { indexes: null }, 
})

まとめ

import axios, { AxiosInstance} from 'axios'

export const axiosClient: AxiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 5000,
  headers: {
    'Content-Type': 'application/json'
  }
+  // デフォルトコンフィグに指定する
+  paramsSerializer: { indexes: null }, 
})

type SearchFilter = {
  arr: number[]
}

type SearchResult = {
  name: number
  age: number
}

export const search = async (filter: SearchFilter): Promise<SearchResult> => {
-  const response = await axiosClient.get<SearchResult>(`/search`, {params:filter})
+ // デフォルトコンフィグに指定しないなら、ここで指定する
+  const response = await axiosClient.get<SearchResult>(`/search`, 
+    {params:filter, paramsSerializer: { indexes: null }})
  return response.data
}

export const sample = async () => {
  const result =  await search({arr: [1, 3, 5, 7]})
  console.log(result)
}

Discussion