![[Swift] AlamofireでURLクエリパラメータに配列を渡す時、ブラケットが付かないようにしたい](https://devio2023-media.developers.io/wp-content/uploads/2018/12/eyecatch-swift.png)
[Swift] AlamofireでURLクエリパラメータに配列を渡す時、ブラケットが付かないようにしたい
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
CX事業本部の中安です。まいどです。
ネットワーク通信ライブラリの代表格であるAlamofireを使用したアプリを開発しているのですが、
とあるGETで取得するAPIに通信しようとする際に、URLクエリパラメータの仕様で少し悩ましい部分がありました。
その仕様とは「ひとつのキーに複数の値を渡すときに、その個数分だけそのキーを使う」というものです。
文章だとわかりづらいので、例を出してみます。
https://(APIのエンドポイント)?loc=tokyo&loc=osaka&loc=nagoya&date=20230509
この例では、locというキーに対して tokyo osaka nagoyaという複数の値を渡そうとしています。
APIの仕様としてスタンダードなのかどうかは分かりませんが、こういう仕様なのでそれに合わせないといけません。
このうえで、Alamofireに対してはEncodableなリクエストパラメータオブジェクトを渡すことになっています。
それは、次項で例示したいと思います。
元々のソースコード
こちらが実際に開発していたアプリに近しい作りのソースコードです。
リクエストパラメータ用の構造体を定義し、それをインスタンス化して、Alamofireのセッション(AF)に渡してリクエストしています。
// リクエストパラメータの定義
struct ExampleAPIRequestParameters: Encodable {
let date: String
let location: String
enum CodingKeys: String, CodingKey {
case date
case location = "loc"
}
}
// リクエストパラメータオブジェクトの作成
let params = ExampleAPIRequestParameters(
date: "20230509",
location: "tokyo"
)
// Alamofireを使用したリクエスト実行
let url = "http://(APIのエンドポイント)"
AF.request(url, method: .get, parameters: params).responseData { response in
// 何か処理
}
しかし、上記のソースコードではlocは複数の値を渡せません。
文字列配列に変える
locに複数の値を渡すには、もちろん文字列型を文字列配列型に変えるわけです。
struct ExampleAPIRequestParameters: Encodable {
let date: String
let locations: [String]
enum CodingKeys: String, CodingKey {
case date
case locations = "loc"
}
}
let params = ExampleAPIRequestParameters(
date: "20230509",
locations: ["tokyo", "osaka", "nagoya"]
)
これで解決と思いきや、残念ながらAlamofireで変換されるURLは以下のようになります。
https://(APIのエンドポイント)?loc[]=tokyo&loc[]=osaka&loc[]=nagoya&date=20230509
URLクエリパラメータで配列であることを示すブラケット([])がついてしまうのです。
URLクエリパラメータの仕様としては間違っていませんが、APIの仕様には合わないものとなってしまいました。
ブラケットを取り払う
このブラケットが付いてしまう原因は、Alamofireが用意するパラメータエンコーダが関与しています。
AF.request()をする際に、パラメータエンコーダは指定しない限りはURLEncodedFormParameterEncoder.defaultという定義のエンコーダを使用し、その中身は「配列にはブラケットを付けよ」という設定がなされているのでした。
なので、ブラケットを取り払うにはデフォルトのものは使用せず、自分でエンコーダを作ってあげる必要があります。
// 「配列にはブラケットを付けない」という設定のエンコーダを作成する
let arrayToNoBracketsURLEncoder = URLEncodedFormEncoder(arrayEncoding: .noBrackets)
// 上記のものをエンコーダに設定したパラメータエンコーダを作成する
let parameterEncoder = URLEncodedFormParameterEncoder(encoder: arrayToNoBracketsURLEncoder)
// リクエスト時に上記のパラメータエンコーダを渡して実行する
let url = "http://(APIのエンドポイント)"
AF.request(url, method: .get, parameters: params, encoder: parameterEncoder).responseData { response in
// 何か処理
}
こうすることにより、求めていたパラメータの形式でリクエストがされるようになりました。
https://(APIのエンドポイント)?loc=tokyo&loc=osaka&loc=nagoya&date=20230509
このように、ちょっと変わった仕様のAPIに対してもクエリパラメータのフォーマットを変更することができるようになります。
指定できる配列のフォーマット
ここでは ArrayEncodingを.noBracketsを指定しましたが、他にはどんな設定ができるかというと
- .brackets: ブラケットをつける
loc[]=tokyo&loc[]=osaka&loc[]=nagoya - .noBrackets: ブラケットをつけない
loc=tokyo&loc=osaka&loc=nagoya - .indexInBrackets: ブラケットに添字をつける
loc[0]=tokyo&loc[1]=osaka&loc[2]=nagoya
その他指定できる設定
ここまで紹介した配列のフォーマットの他にも、URLEncodedFormEncoderを作る際には以下のような設定を施すことが可能です。
- alphabetizeKeyValuePairs: キーをアルファベット順に並べるかどうか
- arrayEncoding: 配列のフォーマット (ここまで述べた通り)
- boolEncoding: Bool型を
true/false1/0で記述するかを設定できる - dataEncoding: バイナリデータをBase64や他の形式でクエリ化できる
- dateEncoding: 日付型をどのような形式で文字列化するかを設定できる
- keyEncoding: キー名をキャメルケースやスネークケースに変えることができる
- spaceEncoding: 空白スペースを「+」にしたり、エスケープ文字にすることができる
- allowedCharacters: 使用できる文字を制御できる
終わりに
AlamofireでURLクエリパラメータを指定する際には、それなりに柔軟なフォーマットや設定に対応してくれていることがわかりました。
もし、同じようなところで躓いた方の何かの参考になれば幸いです。
では、またー










