2

I have a post request that I want to make using URLSession.

The post request looks like this:

curl -X POST   'https://smartdevicemanagement.googleapis.com/v1/enterprises/privatekey/devices/devicekey:executeCommand'   -H 'Content-Type: application/json'   -H 'Authorization: authtoken'   --data-raw '{
"command" : "sdm.devices.commands",
"params" : {
  "commandName" : "cmdValue"
 }
}'

As this is a POST request, I want to only decode if the response is an error message.

Here is the code I currently have:

guard let url = URL(string: "https://smartdevicemanagement.googleapis.com/v1/enterprises/\(project_id)/devices") else {return}
    
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("token", forHTTPHeaderField: "Authorization")
let cmdParams: [String: String] =  ["command":"sdm.devices.commands", "params" : ["commandName": "cmdValue"]]

do {
    request.httpBody = try JSONSerialization.data(withJSONObject: cmdParams)
} catch let error {
    print(error.localizedDescription)
    }

URLSession.shared.dataTask(with: request) { (data, response, error) in
    guard error == nil else {print(error!.localizedDescription); return }
    guard let data = data else {print("empty data"); return }

The cmdParams are throwing an error, so I'm not sure how to structure the params request properly, a successful POST will result in the API returning {} an unsuccessful request will return some error.

How can I adjust my code to get this working?

8
  • cmdParams is [String:Any], not [String:String] Commented Dec 23, 2021 at 16:37
  • @vadian thanks made that change but still can't get the request to POST. Commented Dec 23, 2021 at 16:44
  • [String:Any] isn't codable. You either need to create a struct to encode the data or directly use a JSON string (as in my answer). Commented Dec 23, 2021 at 17:15
  • @BjornB. JSONSerialization can serialize [String:Any]. It's not about Codable Commented Dec 23, 2021 at 17:22
  • @vadian You are right. Commented Dec 23, 2021 at 17:23

3 Answers 3

4

You need to encode the JSON string as data. Then you can add it as the httpBody. Don't forget to add the token to the request.

// Encode your JSON data
let jsonString = "{ \"command\" : \"sdm.devices.commands\", \"params\" : { \"commandName\" : \"cmdValue\" } }"
guard let jsonData = jsonString.data(using: .utf8) else { return } 

// Send request
guard let url = URL(string: "https://smartdevicemanagement.googleapis.com/v1/enterprises/\(project_id)/devices") else {return}
    
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = jsonData

request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("token", forHTTPHeaderField: "Authorization") // Most likely you want to add some token here
// request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")

let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
    if let error = error {
        // Handle HTTP request error
    } else if let data = data {
        // Handle HTTP request response
    } else {
        // Handle unexpected error
    }
}
task.resume()
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks, there's no error messages now but the POST data is still not going through, is there any way I can modify this code to print what the API call is responding with?
You can, you can print the data and the response. Take a look the dataTask documentation: developer.apple.com/documentation/foundation/urlsession/…
Ok i got a response code 500 which indicates something is wrong with the server I am requesting from right?
500 usually is an internal server error. Do you have a status message or response body?
1

You could try using "urlencoded" to encode your request body. Here is my test code: (note, since I do not have a paid subscription to this service I cannot fully test my code)

struct ContentView: View {
    let project_id = 123  // <-- adjust to your needs
    
    var body: some View {
        Text("testing")
            .onAppear {
                if let url = URL(string: "https://smartdevicemanagement.googleapis.com/v1/enterprises/\(project_id)/devices") {
                    doPOST(url: url)
                }
            }
    }
    
    func doPOST(url: URL) {
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        // try urlencoding
        request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        request.setValue("token", forHTTPHeaderField: "Authorization") // <-- your api "token" here
        
        var components = URLComponents(url: url, resolvingAgainstBaseURL: false)!
        components.queryItems = [
            URLQueryItem(name: "command", value: "sdm.devices.commands"),
            URLQueryItem(name: "params", value: "{ \"commandName\" : \"cmdValue\" }")
        ]
        if let query = components.url!.query {
            print("--> query: \(query)")
            request.httpBody = Data(query.utf8)
        }
        
        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            showResponse(data)  // <-- for debuging
            guard error == nil else { print("--> error: \(error)"); return }
            guard let data = data else { print("empty data"); return }
        }
        task.resume()
    }
    
    func showResponse(_ data: Data?) {
        if let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers), let jsonData = try? JSONSerialization.data(withJSONObject: json, options: .prettyPrinted) {
            print("\n---> response: " + String(decoding: jsonData, as: UTF8.self))
        } else {
            print("=========> error")
        }
    }
    
}

If this does not work, have a look at this doc:

https://developers.google.com/nest/device-access/reference/rest/v1/enterprises.devices/executeCommand

In particular: The URL uses gRPC Transcoding syntax. It may be relevant.

Comments

0
func postRequest(email: String, password: String, onsuccess: @escaping ((Loginproduct?) -> Void)) {
    let url = URL(string: "https://app.omana-app.com/api/login")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("sk_d3KmPtjEtdGTjChLB0ylraAb/AWgfyR9MOxFXwgEWSZsnpoIXFVDfm1Snoak0ufRe0w=", forHTTPHeaderField: "secret_key")
    request.addValue("pk_Bvk6rVC7WxbRW2O3sy4xwCEiM+n8jdT55BQv4BA0zG4IawzpbDhTVzSvj43DcvU7cM0x", forHTTPHeaderField: "publish_key")

    let params: [String: Any] = [
        "email": email,
        "password": password,
        "device_type": 2,
        "device_token": "abc",
        "role": "4"
    ]

    do {
        request.httpBody = try JSONSerialization.data(withJSONObject: params, options: [])

        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            if let response = response as? HTTPURLResponse {
                let statusCode = response.statusCode
                print("status code = \(statusCode)")

                if statusCode == 200 {
                    if let data = data {
                        do {
                            let decoder = JSONDecoder()
                            let loginResponse = try decoder.decode(Loginproduct.self, from: data)

                            // Pass the decoded model to the completion handler
                            onsuccess(loginResponse)
                        } catch {
                            print("Error decoding JSON: \(error)")
                            // Pass nil in case of decoding error
                            onsuccess(nil)
                        }
                    }
                }
            } else if let error = error {
                print("Error: \(error)")
                // Pass nil in case of network error
                onsuccess(nil)
            }
        }

        task.resume()
    } catch {
        print("Error creating JSON body: \(error)")
        onsuccess(nil)
    }
}

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.