daltoniam / SwiftHTTP

Thin wrapper around NSURLSession in swift. Simplifies HTTP requests.
Apache License 2.0
1.88k stars 313 forks source link

How to debug the HTTP.GET calls #264

Closed jsiddharth closed 7 years ago

jsiddharth commented 7 years ago

Migrated from Alamofire to SwiftHTTP, since I found this much easier.

But there is no way to know what URL got generated, what error it returned. For example, I tried to see the debugDescription variable, it returned something cryptic like description String "<SwiftHTTP.HTTP: 0x60000007e540>"

var getData = [String:String]()
        getData = ["domain": "4345",
            "driver" : "2343",
            "key" : "asdfasdf"]

        var urlComponents = URLComponents(string: fullURL)!
        var queryItems = [URLQueryItem]()
        queryItems = self.getData.map{ URLQueryItem(name : $0.0, value : $0.1) }
        urlComponents.queryItems = queryItems
        print("fullurl ->"+(urlComponents.url)!.absoluteString)

do {
            let opt = try HTTP.GET((urlComponents.url)!.absoluteString)
                       opt.start { response in
                if let err = response.error {
                    print("--1-> error: \(err.localizedDescription)")
                    return //also notify app of failure as needed
                }
                print("--2--> opt finished: \(response.description)")
                self.responseData = response
            }
        } catch let error {
            print("--3--> got an error creating the request: \(error)")
        }   

--1->, --2-->, --3-->, nothing got printed. I was hoping to debug this, to see what URL got generated, but found no way to do that.

gxnews8 commented 7 years ago

In this short blog post I am going to share with you how to create and send HTTP GET Request with one request parameter. I will also show you how to add Basic Authorization header or how to add custom Token Auth header value to your HTTP request.

For this particular example I have created a Single View Application with one ViewController only. My UI is also very basic. I have one UITextField which will accept userName value and a button which user needs to tap to send HTTP Request.

HTTP GET Example in Swift

When user taps on Send button we will trigger following function:

@IBAction func sendButtonTapped(sender: AnyObject) { } The above function is not ready to be used with our project as is of course and we need to add some business login to it. And the first step for us will be to get the value from UITextFiled and check if this value is not empty. To do that we will first create an outlet for UITextField. Place the IBOutlet right under the class declaration like so:

class ViewController: UIViewController { @IBOutlet weak var userNameTextField: UITextField! ... Now lets modify our function “sendButtonTapped” and make it look like so:

@IBAction func sendButtonTapped(sender: AnyObject) {
// Read textValue user inputs into userNameValue variable let userNameValue = userNameTextField.text

// Check of userNameValue is not empty if isStringEmpty(userNameValue!) == true { return } // If we reach here then we can send http request } The isStringEmpty is custom function which we need to implement. Let’s create a new function which will check the value provided for empty string and will return true if it is so.

func isStringEmpty(var stringValue:String) -> Bool { var returnValue = false

    if stringValue.isEmpty  == true
    {
        returnValue = true
        return returnValue
    }

   // Make sure user did not submit number of empty spaces
    stringValue = stringValue.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())

    if(stringValue.isEmpty == true)
    {
        returnValue = true
        return returnValue

    }

      return returnValue

}

Now we can continue with our sendButtonTapped function and add code that sends HTTP GET Request. I will write below a compete implementation of the function and in the comments to my code explain its business logic line by line.

@IBAction func sendButtonTapped(sender: AnyObject) { let userNameValue = userNameTextField.text

    if isStringEmpty(userNameValue!) == true
    {
        return
    }

    // Send HTTP GET Request 

    // Define server side script URL 
    let scriptUrl = "http://swiftdeveloperblog.com/my-http-get-example-script/"
    // Add one parameter
    let urlWithParams = scriptUrl + "?userName=\(userNameValue!)"
    // Create NSURL Ibject
    let myUrl = NSURL(string: urlWithParams);

    // Creaste URL Request
    let request = NSMutableURLRequest(URL:myUrl!);

    // Set request HTTP method to GET. It could be POST as well
    request.HTTPMethod = "GET"

    // If needed you could add Authorization header value
    // Add Basic Authorization
    /*
    let username = "myUserName"
    let password = "myPassword"
    let loginString = NSString(format: "%@:%@", username, password)
    let loginData: NSData = loginString.dataUsingEncoding(NSUTF8StringEncoding)!
    let base64LoginString = loginData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
    request.setValue(base64LoginString, forHTTPHeaderField: "Authorization")
    */

    // Or it could be a single Authorization Token value
    //request.addValue("Token token=884288bae150b9f2f68d8dc3a932071d", forHTTPHeaderField: "Authorization")

    // Excute HTTP Request
    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
        data, response, error in

        // Check for error
        if error != nil
        {
            print("error=\(error)")
            return
        }

        // Print out response string
        let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
        print("responseString = \(responseString)")

        // Convert server json response to NSDictionary
        do {
            if let convertedJsonIntoDict = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {

                // Print out dictionary
                print(convertedJsonIntoDict)

                // Get value by key
                let firstNameValue = convertedJsonIntoDict["userName"] as? String
                print(firstNameValue!)

            }
        } catch let error as NSError {
            print(error.localizedDescription)
        }

    }

    task.resume()

}

And this it! Pretty simple. Using this example you should be able to send HTTP GET requests to your web service end points. If you would like to see how this project works and be able to debug it here is URL to download it from GitHub. You can also download ZIP archive of this project.

Add Basic Authorization HTTP Request Header Please note that in the function above some of the code is commented out. The commented out code is for adding HTTP Request Header with Authorization value. The server side endpoint that I use does not require Auth token or Basic Authorization to be used. However if your web service endpoint requires Basic Authorization to be used, you can add this code:

    let username = "myUserName"
    let password = "myPassword"
    let loginString = NSString(format: "%@:%@", username, password)
    let loginData: NSData = loginString.dataUsingEncoding(NSUTF8StringEncoding)!
    let base64LoginString = loginData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
    request.setValue(base64LoginString, forHTTPHeaderField: "Authorization")

Add Auth Token to HTTP Request Header or if your RESTful web service requires Auth Token to be provided with HTTP Request Header you can uncomment the following code and add Authorization header with the Auth token value:

request.addValue("Token token=884288bae150b9f2f68d8dc3a932071d", forHTTPHeaderField: "Authorization")

I hope this was helpful!

Happy learning :)! ah, and yes, by the way, below are three videos courses that will help you in your learning process and will provide you with a lot of value if you are learning app development for iOS platform.

acmacalister commented 7 years ago

response.description will return a Response object that contains all the response info from the HTTP Response. HTTP responses generally don't include the URL/URI as the GET request was issued by the client that already knows the URL, as such in your case with the (urlComponents.url)!.absoluteString. Not sure what issue you are seeing, as it that seems like the expected behavior?

gxnews8 commented 7 years ago

You can try it. Thank you.