POST with swift and API

I’ve a problem when I try to send a POST request to my API on my server, I’ve followed many many different tutorials but it still doesn’t work.
I know than my problem is with the POST request but I can’t solve it !
So this is my code in Swift and my API in php : (and yes I’ve replaced the xxxx by the real IDs in my code)

To sum up server receive the request and for example if I manually enter a pseudo it works, It’s really the POST method who doesn’t work.. The server doesn’t receive the POST parameter

  • Run code after a background process - parse.com
  • Background fetch is not working after killing the app
  • Firebase: when to call removeObserverWithHandle in swift
  • What does it mean : “Property type ”JSQMessagesCollectionView“ is incompatible with type ”UICollectionView“, inherited from ”UICollectionViewLayout"
  • Compare Protocol in Swift vs Interface in Java
  • Firebase Storage not working on iMessage extension
  • Swift code :

    var request = NSMutableURLRequest(URL: NSURL(string: "http://localhost:8888/academy/test.php")!)
        var session = NSURLSession.sharedSession()
        request.HTTPMethod = "POST"
    
        var params = ["pseudo":"test"] as Dictionary<String, String>
    
        var err: NSError?
        request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err)
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue("application/json", forHTTPHeaderField: "Accept")
    
        var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
            println("Response: \(response)")
            var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
            println("Body: \(strData)")
            var err: NSError?
            var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: &err) as? NSDictionary
    
            // Did the JSONObjectWithData constructor return an error? If so, log the error to the console
            if(err != nil) {
                println(err!.localizedDescription)
                let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
                println("Error could not parse JSON: '\(jsonStr)'")
            }
            else {
                // The JSONObjectWithData constructor didn't return an error. But, we should still
                // check and make sure that json has a value using optional binding.
                if let parseJSON = json {
                    // Okay, the parsedJSON is here, let's get the value for 'success' out of it
                    var success = parseJSON["success"] as? Int
                    println("Succes: \(success)")
                }
                else {
                    // Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
                    let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
                    println("Error could not parse JSON: \(jsonStr)")
                }
            }
        })
        task.resume()*/
    

    PHP Code :

    $BDD_hote = 'xxxxx';
    $BDD_bd = 'xxxxx';
    $BDD_utilisateur = 'xxxxx';
    $BDD_mot_passe = 'xxxxx';
    
    try{
    $bdd = new PDO('mysql:host='.$BDD_hote.';dbname='.$BDD_bd, $BDD_utilisateur, $BDD_mot_passe);
    $bdd->exec("SET CHARACTER SET utf8");
    $bdd->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
    }
    
    catch(PDOException $e){
    echo 'Erreur : '.$e->getMessage();
    echo 'N° : '.$e->getCode();
    }
    $pseudo = addslashes($_POST["pseudo"]);
    $req = $bdd->query("SELECT * from users WHERE pseudo='$pseudo'");
    $resultArray = array();
    $donnees = $req->fetch();
    echo json_encode($donnees);
    

    Thanks by advance 🙂

    3 Solutions Collect From Internet About “POST with swift and API”

    Try this:

     let myURL = NSURL(string: "http://localhost:8888/academy/test.php")! 
     let request = NSMutableURLRequest(URL: myURL)
     request.HTTPMethod = "POST"
     request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
     request.setValue("application/json", forHTTPHeaderField: "Accept")
     let bodyStr:String = "pseudo=test"
     request.HTTPBody = bodyStr.dataUsingEncoding(NSUTF8StringEncoding) 
     let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
          data, response, error in
    
          // Your completion handler code here
     }
     task.resume()
    

    You have to encode your data using UTF8 string encoding. If you need to set more than one field&value pairs for request body, you can change the body string, for example, “pseudo=test&language=swift”. In fact, I usually create an extension for NSMutableURLRequest and add a method which takes a dictionary as parameter and sets the content of this map(dictionary) as HTTPBody using correct encoding. This may work for you:

     extension NSMutableURLRequest {
          func setBodyContent(contentMap: Dictionary<String, String>) {
               var firstOneAdded = false
               let contentKeys:Array<String> = Array(contentMap.keys)
               for contentKey in contentKeys {
                    if(!firstOneAdded) {
                         contentBodyAsString += contentKey + "=" + contentMap[contentKey]!
                         firstOneAdded = true
                    }
                    else {
                         contentBodyAsString += "&" + contentKey + "=" + contentMap[contentKey]! 
                    }
               }
               contentBodyAsString = contentBodyAsString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
               self.HTTPBody = contentBodyAsString.dataUsingEncoding(NSUTF8StringEncoding)
          }
     }
    

    And you can use this as:

    request.setBodyContent(params)
    

    I hope this helps you!

    As others have pointed out, the encoding of the request is not quite right. Your server code is not expecting JSON request, but rather is using $_POST variables (which means that the request should have Content-Type of application/x-www-form-urlencoded). So that’s what you should create. In Swift 3:

    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    
    let parameters = ["somekey" : "valueforkey"]
    request.setBodyContent(parameters)
    
    request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")
    
    let task = session.dataTask(with: request) { data, response, error in
        guard let data = data, error == nil else {
            print("\(error?.localizedDescription ?? "Unknown error")")
            return
        }
        // your response parsing code here
    }
    task.resume()
    

    The setBodyContent method would take a dictionary of the form ["key1": "foo", "key2" : "bar"] and populate the HTTPBody with something that looks like key1=foo&key2=bar. If you do that, the server will be able to parse the $_POST from the request.

    extension URLRequest {
    
        /// Populate the HTTPBody of `application/x-www-form-urlencoded` request
        ///
        /// - parameter parameters:   A dictionary of keys and values to be added to the request
    
        mutating func setBodyContent(_ parameters: [String : String]) {
            let parameterArray = parameters.map { (key, value) -> String in
                return "\(key.addingPercentEncodingForQuery()!)=\(value.addingPercentEncodingForQuery()!)"
            }
            httpBody = parameterArray.joined(separator: "&").data(using: .utf8)
        }
    }
    

    Note, this also percent-encodes the values, which is critical. While others have advised using addingPercentEncoding, sadly that will not do the job, as it will let certain reserved characters pass unescaped. Notably, in the unlikely situation that the request parameters dictionary’s values contained a & or + character, it would let them pass unescaped (and the & will incorrectly be interpreted as terminating the value and the + will be interpreted as a space). So you have to do your own percent escaping to make sure that only the narrowly defined set of unreserved characters are left unescaped. You could do something like:

    extension String {
    
        /// Percent escape value to be added to a HTTP request
        ///
        /// This percent-escapes all characters besides the alphanumeric character set and "-", ".", "_", and "*".
        /// This will also replace spaces with the "+" character as outlined in the application/x-www-form-urlencoded spec:
        ///
        /// http://www.w3.org/TR/html5/forms.html#application/x-www-form-urlencoded-encoding-algorithm
        ///
        /// - returns: Return percent escaped string.
    
        func addingPercentEncodingForQuery() -> String? {
            let allowed = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._* ")
    
            return addingPercentEncoding(withAllowedCharacters: allowed)?.replacingOccurrences(of: " ", with: "+")
        }
    }
    

    Alternatively, you can build the character set of allowed characters by starting with .urlQueryAllowed, but you still have to remove a few characters as it will otherwise that allows certain characters pass unescaped (e.g. +). See https://stackoverflow.com/a/35912606/1271826.

    For Swift 2 rendition, see previous revision of this answer.

    the following php code is for receiving application/url+encode encoded post message. please refer https://en.wikipedia.org/wiki/Percent-encoding

    $_POST["pseudo"]
    

    and your swift code was sending a JSON encoded string data. They are incompatible.

    If you don’t want to change the php code, in Swift you should send url-encode format message, li:

    // UPDATED with corrections from @Rob

        var params = ["param1":"value1", "papam2": "value 2"]
        var body = ""
        for (key, value) in params {
            body = body.stringByAppendingString(key)
            body = body.stringByAppendingString("=")
            body = body.stringByAppendingString(value.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!)
            body = body.stringByAppendingString("&")
        }
        body = body.substringToIndex(advance(body.startIndex, countElements(body)-1)) // remove the last "&"
        request.HTTPBody = body.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)