Example of Swift and a Put request for a RESTful API
Asked Answered
L

3

5

I'm trying to learn Swift by creating an OSX app for the Phillips Hue light API. However, and I feel silly here, I can't even get a simple example working. I'm using this library in X Code 6.1: https://github.com/hallas/agent

Here's the code I'm using:

import Foundation



let done = { (response: NSHTTPURLResponse!, data: Agent.Data!, error: NSError!) -> Void in
    // react to the result of your request
};
Agent.put("/api/[username]/lights/2/state", headers: [ "Header": "Value" ],
    data: [ "hue": 35000 ], done: done)

Needless to say its not doing anything. What am I doing wrong?

Lacking answered 28/10, 2014 at 20:12 Comment(7)
How do you know that it is not doing anything?Donitadonjon
I'm using the Phillips Hue web interface, and doing a GET for the status of all bulbs. The numbers haven't changed.Lacking
Your done closure is empty; perhaps Agent.put() it is reporting an error? Use if error != null { /* print something; debugger break; etc */ }Donitadonjon
Not sure whether the Agent follows redirect, possible your server implementation requires a '/' at the end of url. Try it.Carlenecarleton
You need a full URL. "/api/[username]/lights/2/state" does not have a domain. Also, remove the extraneous headers parameter; you're currently sending example values.Pushup
Changing the URL to "10.1.11.222/api/[username]/lights/2/state" and getting rid of the headers doesn't do anything. The program runs successfully, but when I do a GET the value of the hue I'm trying to PUT hasn't changed.Lacking
You need to define the protocol, so if it's a web-based service, the URI will start with http:// or https://Benefit
L
7

This is a sample of a PUT operation, using a simple class to wrap the HTTP functionality:

    let url = NSURL(string:"http://example.com")
    let text = "Text to PUT"
    var myData: NSData? = text.dataUsingEncoding(NSUTF8StringEncoding)
    var headers = Dictionary<String, String>()

    Http().put(url!, headers: headers, data:myData!) { (result) in           
        if result.success {
            if let jsonObject: AnyObject = result.jsonObject {
                println(jsonObject)
            }
        }
    }

class Http {

func put(url: NSURL, headers: Dictionary<String, String>, data: NSData, completionHandler: ((result: HttpResult) -> Void)!) {
    action("PUT", url: url, headers: headers, data: data ) { (result) in
        completionHandler(result: result)
    }
}

func action(verb: String, url: NSURL, headers: Dictionary<String, String>, data: NSData, completionHandler: ((result: HttpResult) -> Void)!) {
    let httpRequest = NSMutableURLRequest(URL: url)
    httpRequest.HTTPMethod = verb

    for (headerKey, headerValue) in headers {
        httpRequest.setValue(headerValue, forHTTPHeaderField: headerKey)
    }
    let task = NSURLSession.sharedSession().uploadTaskWithRequest(httpRequest, fromData: data) { (data, response, error) in
        completionHandler(result: HttpResult(data: data, request: httpRequest, response: response, error: error))
    }
    task.resume()
}
}

class HttpResult {

var request: NSURLRequest
var response: NSHTTPURLResponse?
var data: NSData?
var error: NSError?
var statusCode: Int = 0
var success: Bool = false
var headers : Dictionary<String, String> {
    get {
        if let responseValue = response {
            return responseValue.allHeaderFields as Dictionary<String,String>
        }
        else {
            return Dictionary<String, String>()
        }
    }
}

init(data: NSData?, request: NSURLRequest, response: NSURLResponse?, error : NSError?) {
    self.data = data
    self.request = request
    self.response = response as NSHTTPURLResponse?
    self.error = error
    self.success = false

    if error != nil {
        println("Http.\(request.HTTPMethod!): \(request.URL)")
        println("Error: \(error!.localizedDescription)")
    }
    else {
        if let responseValue = self.response {
            statusCode = responseValue.statusCode
            if statusCode >= 200 && statusCode < 300 {
                success = true
            }
            else {
                println("Http.\(request.HTTPMethod!) \(request.URL)")
                println("Status: \(statusCode)")
                if let jsonError: AnyObject = jsonObject {
                    var err: NSError?
                    var errData = NSJSONSerialization.dataWithJSONObject(jsonError, options:NSJSONWritingOptions.PrettyPrinted, error: &err)
                    var errMessage = NSString(data: errData!, encoding: NSUTF8StringEncoding)                     
                    println("Error: \(errMessage)")
                }
            }
        }
    }
}

var jsonObject: AnyObject? {
    var resultJsonObject: AnyObject?
    var jsonError: NSError?
    if let contentType = headers["Content-Type"] {
        if contentType.contains("application/json") {
            resultJsonObject = NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments, error: &jsonError) as AnyObject?
        }
    }
    return resultJsonObject
}    
}
Lucy answered 6/11, 2014 at 21:0 Comment(2)
Ack, sorry I thought you wanted to do a straight PUT, just saw your question looks Hue SDK specific.Lucy
Yes, it will work great to do a REST API PUT, it just is not specific to Phillips Hue.Lucy
C
1

Before you dig into your code. Please make sure you followed the getting start guide from hue developer webpage http://www.developers.meethue.com/documentation/getting-started

Especially:

1. Find out your bridge ip address. The most simple way could be checking on your router. 

2. Open http://bridge_ip_address/debug/clip.html. You'll get a simple client. Try stuffs there.

After you tested that you can put to change in the clip. Then back to your swift code. As @nickgraef mentioned in comments. The endpoint should be: http://bridge_ip_address/api/[username]/lights/2/state.

Agent.put("http://bridge_ip_address/api/[username]/lights/2/state", headers: [ "Header": "Value" ],
    data: [ "hue": 35000 ], done: nil)
Carlenecarleton answered 5/11, 2014 at 16:51 Comment(0)
B
1

Example with Swift 2

    let url = NSURL(string: "https://yourUrl.com") //Remember to put ATS exception if the URL is not https
    let request = NSMutableURLRequest(URL: url!)
    request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") //Optional
    request.HTTPMethod = "PUT"
    let session = NSURLSession(configuration:NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: nil, delegateQueue: nil)
    let data = "[email protected]&password=password".dataUsingEncoding(NSUTF8StringEncoding)
    request.HTTPBody = data

    let dataTask = session.dataTaskWithRequest(request) { (data, response, error) -> Void in

        if error != nil {

            //handle error
        }
        else {

            let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
            print("Parsed JSON: '\(jsonStr)'")
        } 
    }
    dataTask.resume()
Beautiful answered 3/11, 2015 at 15:19 Comment(1)
why not use a [String: AnyObject] type for data?Belcher

© 2022 - 2024 — McMap. All rights reserved.