0

first of all i would like to say i got the exact same problem as the following question: How to add data to HTTPBody with PUT method in NSURLSession?. But it wasn't answered so i made my own question.

We have written a node API for a school assignment. We've tested the whole API. (The chances of being something wrong there are slim.)

After that i went working on a iOS client to CRUD users. Making a user is going perfectly, but whenever i try to edit a user something strange happens. The data on the server arrives as undefined.

I use the following code to save a user:

func saveUser(user: User, completionHandler: (String?, User?) -> Void) {
    let url = NSURL(string: "https://pokeapi9001.herokuapp.com/api/users/")
    let request = NSMutableURLRequest(URL:url!)
    request.HTTPMethod = "POST"

    let postString = "email=\(user.email)&password=\(user.password!)&role=\(user.role)"
    request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)

    request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData


    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
        data, response, error in
        if error != nil {
            print("error: \(error)")
        }

        do {
            guard let data = data else {
                throw JSONError.NoData
            }
            guard let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary else {
                throw JSONError.ConversionFailed
            }

            //do specific things

        } catch let error as JSONError {
            completionHandler(error.rawValue, nil)
        } catch let error as NSError {
            completionHandler(error.debugDescription, nil)
        }

    }
    task.resume()
}

keep in mind, this is working perfectly (don't know if it is intended to be used like this)

To edit a user i use the following code:

func editUser(user: User, completionHandler: (String?, User?) -> Void) {
    let url = NSURL(string: "https://pokeapi9001.herokuapp.com/api/users/\(user.id!)")
    let request = NSMutableURLRequest(URL:url!)
    request.HTTPMethod = "PUT"

    let postString = "email=\(user.email)&password=\(user.password!)&role=\(user.role)"
    request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)

    request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData

    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
        data, response, error in
        if error != nil {
            print("error: \(error)")
        }

        do {
            guard let data = data else {
                throw JSONError.NoData
            }
            guard let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary else {
                throw JSONError.ConversionFailed
            }

            //do specific things

        } catch let error as JSONError {
            completionHandler(error.rawValue, nil)
        } catch let error as NSError {
            completionHandler(error.debugDescription, nil)
        }
    }
    task.resume()
}

(The original code is a bit longer but i removed parts that had nothing to do with the actual posting of the data)

I have really no idea what i'm doing wrong, could be something small and stupid. Please help.

edit after input from @fiks

To be clear, the problem i am having is that I fill the "postString" the same way in the editUser method as I do in the saveUser method.(At least I think I do) However in the saveUser method the postString seems to be correctly passed through to the API (it creates a new user with the given values). The editUser method does not pass the values through.

If I put a console log on the server it shows all values are "undefined". To test if the postString was correct on the iOS part I printed both strings out. Both of them outputted email=user@test.com&password=test&role=admin

Community
  • 1
  • 1
  • 1
    Not a node.js question. Wrong tag – Abhyudit Jain Nov 03 '16 at 12:36
  • Could you be more specific on the error? Could you also please check the request with Charles and post it here? – fiks Nov 03 '16 at 13:02
  • Sorry Abhyudit, the API is made in Node.js so i thought i should add it in there. – user2145124 Nov 03 '16 at 14:10
  • @fiks the problem i am having is that the data in the let "postString" is working in the POST(addUser) request, however in the PUT(editUser) request it doesn't to work. if i put a print after the let postString = ... the print outputs: email=user@test.com&password=test&role=admin just as intended. But on the server it says all 3 values are undefined. i will add this to my question above to remove futher confusion. Also could you tell me how Charles works? I downloaded it, but it doesn't make me wiser. Thanks for your input btw – user2145124 Nov 03 '16 at 14:22
  • @user2145124. Regarding charles: 1. Run the Charles. 2. Run the app in the simulator. 3. See in the Charles logs all of the requests that your app makes and find the one that is wrong. There you will see all of the details of the request. It would be nice if you could post it here. – fiks Nov 03 '16 at 14:36
  • @fiks not sure if im doing it right but this is what charles shows: http://i66.tinypic.com/2sagwvl.jpg. I will also include is a picture of a postman request (http://i64.tinypic.com/10ol7pf.png). It might help as it shows the request i should be doing, the data i should be sending and the response i'm expecting. Again, thanks for your time – user2145124 Nov 03 '16 at 15:02
  • @fiks Another picture from Charles: http://i64.tinypic.com/wjc0hs.png – user2145124 Nov 03 '16 at 15:11
  • @user2145124 from what I see in the postman request, you are sending a "x-www-form-urlencoded" request. You have to specify it in the code (see example: http://stackoverflow.com/questions/22063959/post-request-using-application-x-www-form-urlencoded ) Regarding Charles: since you are using https, you have to enable proxy for the host. More info here: https://www.charlesproxy.com/documentation/proxying/ssl-proxying/ – fiks Nov 03 '16 at 15:25
  • @fiks, thanks dude, setting the request as "x-www-form-urlencoded" fixed it. Don't know why it did work on the POST request. I'm new to this website, how do i give you credit for this? To be clear, the lines added to the 'PUT' where let postLength = "\(postString.endIndex)" request.setValue(postLength, forHTTPHeaderField: "Content-Length") request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") – user2145124 Nov 08 '16 at 15:20
  • @user2145124 I am glad it helped! I have posted my suggestion as an answer, since it worked for you. You can accept it if you want to give me credit. – fiks Nov 08 '16 at 15:58

1 Answers1

0

From what I see in the postman request, you are sending a x-www-form-urlencoded request.

You have to specify it in the code. See example: POST request using application/x-www-form-urlencoded

Regarding Charles: since you are using https, you have to enable proxy for the host. More info here: https://www.charlesproxy.com/documentation/proxying/ssl-proxying/

Community
  • 1
  • 1
fiks
  • 1,045
  • 9
  • 21