How to send post request through swiftUI in iOS 16.0? - swift

Hey guys I am trying to use the face++ API to detect human body in a picture, but I keep getting 400 bad request. I think there is something wrong with my request code, but I am not sure where. For test, I host a picture on a third-party website just want to know how to get the request right. I will delete the api key later in case someone use it improperly.
private func requestFacePlusAPI() {
let url = URL(string: "https://api-cn.faceplusplus.com/humanbodypp/v1/detect")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("multipart/form-data", forHTTPHeaderField: "Content-type")
let api_key = "TpDqYnF1c5xe_iQzaBkVGkAqflqS3aCP"
let api_secret = "JsDx4hiQUOSXuus8MV21WB4F5YzQnB4B"
guard model.ImageData != nil else { return }
let image_base64 = model.ImageData!.base64EncodedData()
print(model.ImageData!)
print(image_base64)
let data = FacePlusData(api_key: api_key, api_secret: api_secret, image_url: "https://i.postimg.cc/prz1VKTY/Wechat-IMG2.jpg")
guard let uploadData = try? JSONEncoder().encode(data) else {
return
}
let task = URLSession.shared.uploadTask(with: request, from: uploadData) { data, response, error in
if let error = error {
print ("error: \(error)")
return
}
guard let response = response as? HTTPURLResponse,
(200...299).contains(response.statusCode) else {
print (response)
print ("server error")
return
}
if let mimeType = response.mimeType,
mimeType == "application/json",
let data = data,
let dataString = String(data: data, encoding: .utf8) {
print ("got data: \(dataString)")
}
}
task.resume()
}

Seeing the documentation and the cURL sample:
curl -X POST "https://api-us.faceplusplus.com/humanbodypp/beta/detect" -F "api_key=<api_key>" \
-F "api_secret=<api_secret>" \
-F "image_file=#image_file.jpg" \
-F "return_attributes=gender"
You need to send parameters in "URL Encoded Form":
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-type")
...
let uploadData = Data("api_key=\(api_key)&api_secret=\(api_secret)&image_url=https://i.postimg.cc/prz1VKTY/Wechat-IMG2.jpg".utf8)

Related

swiftUI : How I can try to do POST API Call with parameters and headers

class TranslateModel : ObservableObject {
func translateCall() {
guard let url = URL(string: "https://openapi.naver.com/v1/papago/n2mt") else { return }
print(1)
let param = "source=en&target=kr&text=hi"
let paramData = param.data(using: .utf8)
var request = URLRequest(url: url)
print(2)
request.httpMethod = "POST"
request.httpBody = paramData
print(3)
request.addValue("application/x-www-form-urlencoded; charset=UTF-8", forHTTPHeaderField: "Content-Type")
request.addValue("3Bwy8lMkuAgZOyDHm1Z3", forHTTPHeaderField: "X-Naver-Client-Id")
request.addValue("gg391Jc1Ge", forHTTPHeaderField: "X-Naver-Client-Secret")
print(4)
let data = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else { fatalError() }
print(5)
guard error == nil else { fatalError()}
print(6)
guard let response = response as? HTTPURLResponse, response.statusCode >= 200 && response.statusCode < 300 else {return}
print(7)
print(data)
}
}
}
Firstly, Please check my code and screenshot.
I tried to do POST API with parameters and headers.
However, when I call the method, It's not working.
So, I checked the step of method, And found that the URLsession with request was not working.
But, I don't know what the problem is.
I think maybe parameters or headers faults.
could you let me know how I can solve this?

How can I make a POST Request in Swift with parameters using URLSession

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?
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()
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.

How to use cURL requests with Swift URLSession

I have a request that looks like this:
curl --header "token: YOUR TOKEN HERE" --data "a=new_session" site url
I understand and can use it via Terminal but I'm trying to do it with Swift and having some issues understanding how to pass parameters and make a request.
What I've tried:
guard let url = URL(string: siteURL) else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue(token, forHTTPHeaderField: "token")
request.addValue("new_session", forHTTPHeaderField: "a")
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 }
if let str = String(data: data, encoding: .utf8) {
print(str)
}
}.resume()
And that doesn't seem to work, I'm a very new to all this networking stuff and I don't even know why we pass token after ":" and new_session after "=" so I would appreciate any help!
You're solution is almost correct. You're just incorrectly converting the --data flag from the curl request. The format of your data is form encoded because it has the format of key=value. So you just need to add the form encoded data (in this case a=new_session) to the body of your HTTP request instead of as a header. Also, make sure to set the proper content type.
It would look something like this:
func makeRequest(siteURL: String, token: String) {
guard let url = URL(string: siteURL) else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue(token, forHTTPHeaderField: "token")
// These two lines are what you were missing.
request.httpBody = "a=new_session".data(using: .utf8)!
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request) { (data, response, error) in
// handle the request
}.resume()
}
The URLSession request and curl request should be equivalent now.

Swift API call with URLSession gives 504 error

I have an API call with oauth which I tested with correct authorization token in postman.I am getting proper response in postman. But when I try same thing in Swift, I get 504 error.
I have checked every params and headers properly and everything looks same as postman. Not sure why samething is working in postman and gives 504 error in swift. what could be issue?
var params = [String : String]()
params["Id"] = Id;
var headers = [String : String]()
headers["api-key"] = "XXXXXX"
headers["Authorization"] = "Bearer XXX"
do{
var request = URLRequest(url: URL(string: getURL())!)
request.allHTTPHeaderFields = headers
request.httpBody = try JSONSerialization.data(withJSONObject: params , options: [])
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
let httpResponse = response as! HTTPURLResponse
print(httpResponse)
}
task.resume()
}catch{
}
When using a GET request, there is no body to the request. Everything goes on the URL.
Also are you sure that in Postman you are using only those 2 headers?
See if something like this works for you:
var params: Parameters = Parameters()
params.updateValue(Id, forKey: "Id")
var components = URLComponents(string: getURL())!
components.queryItems = params.map { (key, value) in
URLQueryItem(name: key, value: value)
}
components.percentEncodedQuery = components.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B")
let request = URLRequest(url: components.url!)
request.setValue("XXXXXX", forHTTPHeaderField: "api-key")
request.setValue("Bearer XXX", forHTTPHeaderField: "Authorization")
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
}
task.resume()

How to perform a curl request in swift?

I am trying to use an external API, which has an API request that is like the following. I am used to requests with just one url, but what do I do with the "H" and the "d" arguments? Should I include them in my url or
$ curl -X POST https://api.lucidtech.ai/v0/receipts \
-H 'x-api-key: <your api key>' \
-H 'Content-Type: application/json' \
-d '{"documentId": "a50920e1-214b-4c46-9137-2c03f96aad56"}'
Currently I have the following code, but where do I place the API key and the document id in this code?
#IBAction func getScannedData(_ sender: Any){
guard let url = URL(string: "https://api.lucidtech.ai/v0/receipts") else {return}
let session = URLSession.shared
session.dataTask(with: url) { (data, response, error) in
if let response = response{
print(response)
}
}
This is an example of how you can translate the curl command into URLRequest:
guard let url = URL(string: "https://api.lucidtech.ai/v0/receipts"),
let payload = "{\"documentId\": \"a50920e1-214b-4c46-9137-2c03f96aad56\"}".data(using: .utf8) else
{
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("your_api_key", forHTTPHeaderField: "x-api-key")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = payload
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 }
if let str = String(data: data, encoding: .utf8) {
print(str)
}
}.resume()