Search code examples
iosswiftweb-servicesswift3asmx

Swift - Multiple Parameters to webservice


I have the following code that should send a username and password off to a webservice, in return I get a single integer back:

 func attemptLogin() {

        let url:URL = URL(string: endpoint+"/LoginNew")!
        let session = URLSession.shared

        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData

        let postString = "username="+txtUsername.text! + "; password="+txtPassword.text!
        request.httpBody = postString.data(using: String.Encoding.utf8)

        let task = session.dataTask(with: request as URLRequest) {
            (
            data, response, error) in

            guard let data = data, let _:URLResponse = response, error == nil else {
                print("error")
                return
            }

            let dataString =  String(data: data, encoding: String.Encoding.utf8)
            print(dataString)

        }

        task.resume()

    }

In my function I need to add two parameters are I'm trying to do in this line:

 let postString = "username="+txtUsername.text! + "; password="+txtPassword.text!
        request.httpBody = postString.data(using: String.Encoding.utf8)

I am getting the following response from my web service when I run this however

Optional("Missing parameter: password.\r\n")

I am obviously not appending the parameters to the request properly but I'm not sure what I've done wrong.


Solution

  • It is good practice to avoid using explicit unwraps of optionals (using !), use guard let for text i UITextFields instead.

    And why not separate into two methods, attemptLogin and login, which maybe can take a closure for code to execute when sign in completed? Maybe the closure can take an Result enum.

    Like this:

    typealias Done = (Result) -> Void
    
    enum MyError: Error {
        case unknown
    }
    
    enum Result {
        case success(String)
        case failure(MyError)
    
        init(_ error: MyError) {
            self = .failure(error)
        }
    
        init(_ dataString: String) {
            self = .success(dataString)
        }
    }
    
    func login(username: String, password: String, done: Done? = nil) {
        let session = URLSession.shared
        guard 
            let url = URL(string: endpoint+"/LoginNew"),
        else { return }
    
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
        let postString = "username=\(username)&password=\(password)"
        request.httpBody = postString.data(using: String.Encoding.utf8)
        let task = session.dataTask(with: request) {
            (data, response, error) in
            guard let data = data else { done?(Result(.unknown)); return }
            let dataString =  String(data: data, encoding: String.Encoding.utf8)
            done?(Result(dataString))
        }
    
        task.resume()
    }
    
    func attemptLogin() {
        guard 
            let username = txtUsername.text,
            let password = txtPassword.text
        else { return }
    
        login(username: username, password: password) {
            result in
            swicth result {
                case .success(let dataString):
                    print(dataString)
                case .failure(let error):
                    print("Failed with error: \(error)")
            }
        }
    }
    

    Disclaimer: Have not tested the code above, but hopefully it compiles (at least with very small changes).