URL
Swift
URLComponents

Swift で URL のクエリストリングを簡単に追加したい

More than 1 year has passed since last update.

やりたいこと

Swift で URL のクエリストリングを簡単に追加したい
例)"https://qiita.com" -> "https://qiita.com?name=value"

環境

Swift 4.0

冗長になりやすい

Swift では文字列結合やURLComponentsを利用することでクエリストリングの追加が可能ですが、いずれも冗長な書き方となってしまいます。

  • 文字列結合を行う場合
let url = URL(string: "https://qiita.com")!
let queryStringAddedUrl = URL(string: 
    url.description.description + (nil == url.query ? "?" : "&") + "name=value"
) // https://qiita.com?name=value
  • URLComponentsを使用する場合
let url = URL(string: "https://qiita.com")!
var components = URLComponents(url: url, resolvingAgainstBaseURL: nil != url.baseURL)
components?.queryItems = [URLQueryItem(name: "name", value: "value")] + (components?.queryItems ?? [])
let queryStringAddedUrl = components?.url // https://qiita.com?name=value

簡潔にしてみた

簡潔に書きたかったのでURLに Extension を実装しました。

URL+.swift
extension URL {

    // クエリを一つ追加した新しいURLを返す
    func queryItemAdded(name: String,  value: String?) -> URL? {
        return self.queryItemsAdded([URLQueryItem(name: name, value: value)])
    }

    // クエリを複数追加した新しいURLを返す
    func queryItemsAdded(_ queryItems: [URLQueryItem]) -> URL? {
        guard var components = URLComponents(url: self, resolvingAgainstBaseURL: nil != self.baseURL) else {
            return nil
        }
        components.queryItems = queryItems + (components.queryItems ?? [])
        return components.url
    }

}

使ってみるとこうなります。シンプルです。

let queryStringAddedUrl = url.queryItemAdded(name: "name",  value: "value") // https://qiita.com?name=value

これだと困ること

  • 同一キーなクエリを追加する必要がある場合
  • String? 以外の型のまま追加したくなる場合

にはこれだけだと対応が難しいです。上の Extension を拡張していくのも良いですが、ググるとURLQueryBuilderのようなライブラリがあるので手を出してみるのもいいかもしれません。