How to perform a curl request in swift? - 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()

Related

How to send post request through swiftUI in iOS 16.0?

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)

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.

Trying to fetch some data from API in swift, and I am getting lost, what am I doing wrong?

Trying to get AI generated text from deepai.com
the example they provided looks like this:
curl \
-F 'text=YOUR_TEXT_HERE' \
-H 'api-key:quickstart-QUdJIGlzIGNvbWluZy4uLi4K' \
https://api.deepai.org/api/text-generator
and I'm trying to reproduce the same in swift:
var request = URLRequest(url: url)
request.setValue("quickstart-QUdJIGlzIGNvbWluZy4uLi4K", forHTTPHeaderField: "api-key")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body = ["text": "Donald Trump"]
let bodyData = try? JSONSerialization.data(withJSONObject: body, options:[])
request.httpMethod = "POST"
request.httpBody = bodyData
URLSession.shared.dataTask(with: request){ (data, responce, error) in
print(responce!)
if let error = error {
print(error)
} else if let data = data {
print(data)
}
}.resume()
I get status code 400. Don't get deep into my optionals unwrapping and so on. Just tell what am I doing wrong? Why curl works and my swift code doesn't?
UPDATE
tried the solution from the suggested question/answer concerning multipart form-data, still not working. Please take a look
var request = URLRequest(url: url)
let boundary = UUID().uuidString
request.setValue("quickstart-QUdJIGlzIGNvbWluZy4uLi4K", forHTTPHeaderField: "api-key")
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let body = ["text": "Donald Trump"]
var data = Data()
for(key, value) in body{
// Add the reqtype field and its value to the raw http request data
data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
data.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".data(using: .utf8)!)
data.append("\(value)".data(using: .utf8)!)
}
data.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
request.httpMethod = "POST"
//request.httpBody = data
URLSession.shared.uploadTask(with: request, from: data){ (data, responce, error) in
print(responce!)
if let error = error {
print(error)
} else if let data = data {
print(data)
}
}.resume()
Don't be mad with my stupidity!)

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.

Use CURL from API

I am new with APIs and I am trying to import data from the API of Schiphol Airport. First I tried this link in my query, but then I got the following result.
https://api.schiphol.nl/public-flights/flights?app_id=////APPID////&app_key=////APPKEY////&includedelays=false&page=0&sort=%2Bscheduletime
result: {code = 406; description = "Can't retrieve version number from accept-header";}
I think that I have to use the CURL to get a result, but I don't know how to do that in SWIFT 3.
CURL: curl -X GET --header "Accept: application/json" --header "ResourceVersion: v3" "https://api.schiphol.nl/public-flights/flights?app_id=////APPID////&app_key=////APPKEY////&includedelays=false&page=0&sort=%2Bscheduletime"
My code now looks like this:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let url = NSURL(string: "https://api.schiphol.nl/public-flights/flights?app_id=////APPID////&app_key=////APPKEY////&scheduledate=2017-07-11&airline=CND&includelays=false&page=0&sort=%2Bscheduletime")!
let task = URLSession.shared.dataTask(with: url as URL) { (data, response, error) -> Void in
if let urlContent = data {
do{
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers)
print(jsonResult)
} catch{
print("failed")
}
}
}
task.resume()
}
Can somebody help me out?
Instead of a simple URL use an URLRequest and add the header field.
This is the Swift equivalent of the cURL syntax:
let url = URL(string: "https://api.schiphol.nl/public-flights/flights?app_id=xxxxxxx&app_key=yyyyyyyyyyyyy5&scheduledate=2017-07-11&airline=CND&includelays=false&page=0&sort=%2Bscheduletime")!
var request = URLRequest(url: url)
request.addValue("v3", forHTTPHeaderField: "ResourceVersion")
let task = URLSession.shared.dataTask(with: request) { (data, response, error) -> Void in ...
I made the personal data anonymous.
Note: Don't pass any options in JSONSerialization, the option .mutableContainers is completely useless in Swift.
let jsonResult = try JSONSerialization.jsonObject(with: urlContent)
According to the API documents you need to set the ResourceVersion in the headers for the call.
The following should work:
var req = URLRequest.init(url: URL.init(string: "https://api.schiphol.nl/public-flights/flights?app_id=//APPID//&app_key=//APPKEY//")!)
req.setValue("v3", forHTTPHeaderField: "ResourceVersion")
URLSession.shared.dataTask(with: req) { (data, response, error) in
print(try? JSONSerialization.jsonObject(with: data!, options: .init(rawValue: 4)))
}.resume()