How can I build a URL with query parameters containing multiple values for the same key in Swift?

All you need is URLComponents (or NSURLComponents in Obj-C). The basic idea is to create a bunch of query items for your id's. Here's code you can paste into a playground:

import Foundation
import XCPlayground

let queryItems = [URLQueryItem(name: "id", value: "1"), URLQueryItem(name: "id", value: "2")]
var urlComps = URLComponents(string: "www.apple.com/help")!
urlComps.queryItems = queryItems
let result = urlComps.url!
print(result)

You should see an output of

www.apple.com/help?id=1&id=2


Method 1

It can add the QueryItem to your existing URL.

extension URL {

    func appending(_ queryItem: String, value: String?) -> URL {

        guard var urlComponents = URLComponents(string: absoluteString) else { return absoluteURL }

        // Create array of existing query items
        var queryItems: [URLQueryItem] = urlComponents.queryItems ??  []

        // Create query item
        let queryItem = URLQueryItem(name: queryItem, value: value)

        // Append the new query item in the existing query items array
        queryItems.append(queryItem)

        // Append updated query items array in the url component object
        urlComponents.queryItems = queryItems

        // Returns the url from new url components
        return urlComponents.url!
    }
}

How to use

var url = URL(string: "https://www.example.com")!
let finalURL = url.appending("test", value: "123")
                  .appending("test2", value: nil)

Method 2

In this method, the URL will be updated automatically.

extension URL {

    mutating func appendQueryItem(name: String, value: String?) {

        guard var urlComponents = URLComponents(string: absoluteString) else { return }

        // Create array of existing query items
        var queryItems: [URLQueryItem] = urlComponents.queryItems ??  []

        // Create query item
        let queryItem = URLQueryItem(name: name, value: value)

        // Append the new query item in the existing query items array
        queryItems.append(queryItem)

        // Append updated query items array in the url component object
        urlComponents.queryItems = queryItems

        // Returns the url from new url components
        self = urlComponents.url!
    }
}

// How to use
var url = URL(string: "https://www.example.com")!
url.appendQueryItem(name: "name", value: "bhuvan")

func queryString(_ value: String, params: [String: String]) -> String? {    
    var components = URLComponents(string: value)
    components?.queryItems = params.map { element in URLQueryItem(name: element.key, value: element.value) }

    return components?.url?.absoluteString
}