Creating URL from String(with encoding)

82 Views Asked by At

I am trying to create URL from String like the following

let searchParam = "?name=movies&Genre=#Action"

func searchMovies(searchString: String) {
    let encodedString = searchParam.encodeSearchString()
    let urlString = "https://search.movies.local/list.html" + encodedString

    guard let url = URL(string: searchParam) else {
        return
    }

    print("URL: ", url)
}

func encodeSearchString() -> String? {
  let unreserved = "#?=&"
  let allowed = NSMutableCharacterSet.alphanumeric()
  allowed.addCharacters(in: unreserved)
  return addingPercentEncoding(withAllowedCharacters: allowed as CharacterSet)
}

It works fine when the search param is "?name=movies&Genre=#Action" but if the search param contains more than one #, then the URL is nil.

For eg., if the searchParam is "?name=#movies&Genre=#Action"

1

There are 1 best solutions below

2
vadian On

The problem is that the # character is the separator for the fragment of the URL.

The most reliable way to build an URL with multiple components is URLComponents and URLQueryItem, the encoding is free

func searchMovies(with parameters: [String:String]) {
    var urlComponents = URLComponents(string: "https://search.movies.local/list.html")!
    var queryItems = [URLQueryItem]()
    for (key, value) in parameters {
        queryItems.append(URLQueryItem(name: key, value: value))
    }
    if !queryItems.isEmpty { urlComponents.queryItems = queryItems }
    print("URL: ", urlComponents.url) // https://search.movies.local/list.html?genre=%23action&name=%23movie
}


searchMovies(with: ["name":"#movie","genre":"#action"])

Or

func searchMovies(by query: String?) {
    var urlComponents = URLComponents(string: "https://search.movies.local/list.html")!
    var queryItems = [URLQueryItem]()
    if let queryString = query {
        let queryPairs = queryString.components(separatedBy: "&")
        for aPair in queryPairs {
            let keyValue = aPair.components(separatedBy: "=")
            if keyValue.count != 2 { continue }
            queryItems.append(URLQueryItem(name: keyValue[0], value: keyValue[1]))
        }
        if !queryItems.isEmpty { urlComponents.queryItems = queryItems }
    }
    print("URL: ", urlComponents.url) // https://search.movies.local/list.html?genre=%23action&name=%23movie
}

searchMovies(by: "name=#movies&Genre=#Action")