Use CURL from API - swift

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

Related

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.

Calling Cloud Function from Swift with JSON data

I have a Cloud Function hosted on Firebase that I am trying to call from a Swift app. It works fine when I call it from command line with the following script, however there is some issue with parsing the JSON data when I call it from swift.
Command Line (works perfectly)
time curl -v -X POST -d '{"url":"https://cdn.bmstores.co.uk/images/hpcProductImage/imgFull/303441-Volvic-6x500ml-Naural-Mineral-Water1.jpg"}' -H "Content-type: application/json" https://us-central1-themagicfactory-5cf7a.cloudfunctions.net/fastMatches
Swift Code (doesn't work)
functions.httpsCallable("fastMatches").call("{\"url\":\"https://cdn.bmstores.co.uk/images/hpcProductImage/imgFull/303441-Volvic-6x500ml-Naural-Mineral-Water1.jpg\"}", completion: {(result,error) in
if let error = error{
print("An error occurred while calling the test function: \(error)" )
}
print("Results from test cloud function: \(result)")
})
Python Pseudo (cloud function)
def fastMatches(request):
print(request)
req = urllib.request.urlopen(request.json["url"])
Request being weird when called from Swift
EDIT: I get the same weird results even if I call it from a manual HTTPs request.
let json: [String: String] = ["url": "https://cdn.bmstores.co.uk/images/hpcProductImage/imgFull/303441-Volvic-6x500ml-Naural-Mineral-Water1.jpg"]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
// create post request
let url = URL(string: "https://us-central1-themagicfactory-5cf7a.cloudfunctions.net/fastMatches")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
// insert json data to the request
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
print(data,response,error)
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON)
}
}
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()

Post data using URLSession

When i try from Alamofire then it work fine but when i try to solve from URLSESSION Swift 4 then i got wrong response.
I checked in postman and it's response was right.
Parameter Description:
I have a key "data" whose value is another dictionary ["answer1":"1","answer2":"2","answer3":"3"]. Need to post this.
Wrong Reposnse = {"message = "Invalid data."; response = failure;}"
Right Reposnse = {"response":"success","message":"Data Inserted”}.
func postData()
{
let BASEURLS = "http://sebamedretail.techizer.in/babystore_api/question_data"
let parameter = ["data":["answer1":"1","answer2":"2","answer3":"3"]]
let session = URLSession.shared
var request = URLRequest.init(url: URL.init(string: BASEURLS)!)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
do
{
request.httpBody = try JSONSerialization.data(withJSONObject:parameter, options: [])
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
do{
let responseArr = try! JSONSerialization.jsonObject(with: data!, options: [])
}
})
task.resume()
}
catch
{}
}
Everything seems fine, maybe you should check the way you extract the JSON in your code, if it's PHP, here could be a solution: https://stackoverflow.com/a/18867369/7452015

How to convert this to a POST call with a JSON serialized Object

I have tried Alamofire, I have tried it with all my heart. It just does not work for me. I finally got http GET working, but I need to get http POST working. Our POST API's take a Request object that has all the necessary data in it. I have requested the backend developers to provide me with a KEY-VALUE pair JSON (no embedded objects/arrays) so that I can use a Dictionary in my swift code convert that to json and send the request. All I need is now to convert the below code to POST.
My earlier questions that did not help much.
NSInvalidArgumentException Invalid type in JSON write DemographicsPojo
Swift 3.0, Alamofire 4.0 Extra argument 'method' in call
I have given up on Alamofire. I want to use Foundation classes. Simple basic and fundamental way of life :).
func callWebService(url : String) {
// Show MBProgressHUD Here
var config :URLSessionConfiguration!
var urlSession :URLSession!
config = URLSessionConfiguration.default
urlSession = URLSession(configuration: config)
// MARK:- HeaderField
let HTTPHeaderField_ContentType = "Content-Type"
// MARK:- ContentType
let ContentType_ApplicationJson = "application/json"
//MARK: HTTPMethod
let HTTPMethod_Get = "GET"
let callURL = URL.init(string: url)
var request = URLRequest.init(url: callURL!)
request.timeoutInterval = 60.0 // TimeoutInterval in Second
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
request.addValue(ContentType_ApplicationJson, forHTTPHeaderField: HTTPHeaderField_ContentType)
request.httpMethod = HTTPMethod_Get
let dataTask = urlSession.dataTask(with: request) { (data,response,error) in
if error != nil{
print("Error **")
return
}
do {
let resultJson = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:AnyObject]
print("Result",resultJson!)
} catch {
print("Error -> \(error)")
}
}
dataTask.resume()
print("..In Background..")
}
Just pass JSON string and the API URL to this function. Complete code for POST.
func POST(api:String,jsonString:String,completionHandler:#escaping (_ success:Bool,_ response:String?,_ httpResponseStatusCode:Int?) -> Void) {
let url = URL(string: api)
var request: URLRequest = URLRequest(url: url!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField:"Content-Type")
request.timeoutInterval = 60.0
//additional headers
if let token = Helper.readAccessToken() {
request.setValue("\(token)", forHTTPHeaderField: "Authorization")
}
let jsonData = jsonString.data(using: String.Encoding.utf8, allowLossyConversion: true)
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) {
(data: Data?, response: URLResponse?, error: Error?) -> Void in
var responseCode = 0
if let httpResponse = response as? HTTPURLResponse {
responseCode = httpResponse.statusCode
print("responseCode \(httpResponse.statusCode)")
}
if error != nil {
completionHandler(false, error?.localizedDescription,nil)
} else {
let responseString = String(data: data!, encoding: .utf8)
completionHandler(true, responseString, responseCode)
}
}
task.resume()
}