x-www-form-urlencoded with URL Components

Hello,


Is it possible to add x-www-form-urlencoded params in URL Component (for example with QueryItem) ?

I am trying to do a sign in / sign up form and I want the username and the password to be x-www-form-urlencoded.



What I currently have :

func signIn(for username : String, for password : String, completion: ((Result<User>) -> Void)?) {
        urlComponents.path = "/users/signin/"
        urlComponents.queryItems = [userIdItem]
        guard let url = urlComponents.url else { fatalError("Could not create URL from components") }
        
        var request = URLRequest(url: url)
        request.httpMethod = "GET"
        
        let config = URLSessionConfiguration.default
        let session = URLSession(configuration: config)
        let task = session.dataTask(with: request) { (responseData, response, responseError) in
            DispatchQueue.main.async {
                if let error = responseError {
                    completion?(.failure(error))
                } else if let jsonData = responseData {
                    let decoder = JSONDecoder()
                    
                    do {
                        let user = try decoder.decode(User.self, from: jsonData)
                        completion?(.success(user))
                    } catch {
                        completion?(.failure(error))
                    }
                } else {
                    let error = NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey : "Data was not retrieved from request"]) as Error
                    completion?(.failure(error))
                }
            }
        }
        
        task.resume()
    }

Thank you a lot

request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")

Is it possible to add x-www-form-urlencoded params in URL Component (for example with QueryItem) ?

No.

x-www-form-urlencoded
is usually used in the
Content-Type
header to indicate that the request body is URL encoded. See Section 17.13.4 of the HTML 4.01 Specification for details. This format is only indirectly related to URLs, and thus is not supported by
URLComponents
.

Creating data in this format is tricky because the specification is so weak. Below you’ll find my take on it.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
enum QHTTPFormURLEncoded {

    static let contentType = "application/x-www-form-urlencoded"

    /// Encodings the key-values pairs in `application/x-www-form-urlencoded` format.
    ///
    /// The only specification for this encoding is the [Forms][spec] section of the 
    /// *HTML 4.01 Specification*.  That leaves a lot to be desired.  For example:
    ///
    /// * The rules about what characters should be percent encoded are murky
    ///
    /// * It doesn't mention UTF-8, although many clients do use UTF-8
    ///
    /// [spec]: <http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4>
    ///
    /// - parameter formDataSet: An array of key-values pairs
    ///
    /// - returns: The returning string.

    static func urlEncoded(formDataSet: [(String, String)]) -> String {
        return formDataSet.map { (key, value) in 
            return escape(key) + "=" + escape(value)
        }.joined(separator: "&")
    }

    /// Returns a string escaped for `application/x-www-form-urlencoded` encoding.
    ///
    /// - parameter str: The string to encode.
    ///
    /// - returns: The encoded string.

    private static func escape(_ str: String) -> String {
        // Convert LF to CR LF, then
        // Percent encoding anything that's not allow (this implies UTF-8), then
        // Convert " " to "+".
        //
        // Note: We worry about `addingPercentEncoding(withAllowedCharacters:)` returning nil 
        // because that can only happen if the string is malformed (specifically, if it somehow 
        // managed to be UTF-16 encoded with surrogate problems) <rdar://problem/28470337>.
        return str.replacingOccurrences(of: "\n", with: "\r\n")
            .addingPercentEncoding(withAllowedCharacters: sAllowedCharacters)!
            .replacingOccurrences(of: " ", with: "+")
    }

    /// The characters that are don't need to be percent encoded in an `application/x-www-form-urlencoded` value.

    private static let sAllowedCharacters: CharacterSet = {
        // Start with `CharacterSet.urlQueryAllowed` then add " " (it's converted to "+" later) 
        // and remove "+" (it has to be percent encoded to prevent a conflict with " ").
        var allowed = CharacterSet.urlQueryAllowed
        allowed.insert(" ")
        allowed.remove("+")
        allowed.remove("/")
        allowed.remove("?")
        return allowed
    }()
}

Im my experience, you can use the URLComponents query property and use it for generating the post body.

Like this:


request.httpBody = getFormDataPostString(params: dic).data(using: .utf8)


func getFormDataPostString(params:[String:String]) -> String

{

var components = URLComponents()

components.queryItems = params.keys.compactMap{

URLQueryItem(name: $0, value: params[$0])

}

return components.query ?? ""

}

x-www-form-urlencoded with URL Components
 
 
Q