If it's possible that the value that you're adding to your URL can have reserved characters (as defined by section 2 of RFC 3986), you might have to refine your percent-escaping. Notably, while &
and +
are valid characters in a URL, they're not valid within a URL query parameter value (because &
is used as delimiter between query parameters which would prematurely terminate your value, and +
is translated to a space character). Unfortunately, the standard percent-escaping leaves those delimiters unescaped.
Thus, you might want to percent escape all characters that are not within RFC 3986's list of unreserved characters:
Characters that are allowed in a URI but do not have a reserved
purpose are called unreserved. These include uppercase and lowercase
letters, decimal digits, hyphen, period, underscore, and tilde.
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
Later, in section 3.4, the RFC further contemplates adding ?
and /
to the list of allowed characters within a query:
The characters slash ("/") and question mark ("?") may represent data
within the query component. Beware that some older, erroneous
implementations may not handle such data correctly when it is used as
the base URI for relative references (Section 5.1), apparently
because they fail to distinguish query data from path data when
looking for hierarchical separators. However, as query components
are often used to carry identifying information in the form of
"key=value" pairs and one frequently used value is a reference to
another URI, it is sometimes better for usability to avoid percent-
encoding those characters.
Nowadays, you'd generally use URLComponents
to percent escape the query value:
var address = "American Tourister, Abids Road, Bogulkunta, Hyderabad, Andhra Pradesh, India"
var components = URLComponents(string: "http://maps.googleapis.com/maps/api/geocode/json")!
components.queryItems = [URLQueryItem(name: "address", value: address)]
let url = components.url!
By the way, while it's not contemplated in the aforementioned RFC, section 5.2, URL-encoded form data, of the W3C HTML spec says that application/x-www-form-urlencoded
requests should also replace space characters with +
characters (and includes the asterisk in the characters that should not be escaped). And, unfortunately, URLComponents
won't properly percent escape this, so Apple advises that you manually percent escape it before retrieving the url
property of the URLComponents
object:
// configure `components` as shown above, and then:
components.percentEncodedQuery = components.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B")
let url = components.url!
For Swift 2 rendition, where I manually do all of this percent escaping myself, see the previous revision of this answer.