I'm trying to find the correct syntax for calling ecobee's API from Swift 4 using Alamofire.

Their cURL example:

curl -H "Content-Type: text/json" -H "Authorization: Bearer ACCESS_TOKEN" 'https://api.ecobee.com/1/thermostat?format=json&body=\{"selection":\{"selectionType":"registered","selectionMatch":"","includeRuntime":true\}\}'

The closest I've been to a solution is this

func doRequest() {
    guard let url = URL(string: "https://api.ecobee.com/1/thermostat?format=json") else { return }

    let parameters: Parameters = [
        "selection": [
            "selectionType": "registered",
            "selectionMatch": ""
        ]
    ]

    let headers: HTTPHeaders = [
        "Content-Type": "text/json",
        "Authorization": "Bearer \(core.accessToken)"
    ]

    let req = AF.request(url, method: .get, parameters: parameters, encoding: JSONEncoding.default, headers: headers)
        .responseJSON { response in
            print("Error:", response.error?.localizedDescription ?? "no error")
            print("Data:", String(data: response.data!, encoding: .utf8)!)
    }

    debugPrint(req)
}

When I run this, the call ultimately fails with status code 408, a server timeout.

When I change the HTTP method to use .post, the call completes, but the response is an internal status 3 with message "Update failed due to a communication error."

Can anyone help me figure out what I'm doing wrong before I waste another day trying to hack my way through it?

1 Answers

0
Jon Shier On Best Solutions

Ecobee's request format is a bit bizarre, as it uses form encoded parameters, but one of the values is a JSON encoded body. You'll have to do a little bit of prep work, as Alamofire doesn't naturally support something like this. This is just sample code, you'll need to do the work to make it safer.

First, encode the JSON parameters and get the String value:

let jsonParameters = ["selection": ["selectionType": "registered", "selectionMatch": ""]]
let jsonData = try! JSONEncoder().encode(jsonParameters)
let jsonString = String(decoding: jsonData, as: UTF8.self)

Then, create the actual parameters and headers values:

let parameters = ["format": "json", "body": jsonString]
let token = "token"
let headers: HTTPHeaders = [.authorization(bearerToken: token), .contentType("text/json")]
let url = URL(string: "https://api.ecobee.com/1/thermostat")!

And make the request:

AF.request(url, parameters: parameters, headers: headers).responseJSON { response in ... }