Sending custom HTTP headers in swift - json

I managed to fetch json from my server but now I want to add extra security by way of http headers. This is how my code barely looks like for now:
let urlPath = "http://www.xxxxxxxx.com"
let url = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!, completionHandler: { (data, response, error) -> Void in
if ((error) != nil) {
println("Error")
} else {
// process json
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary
println(jsonResult["user"])
}
})
The headers that I want to add to this request are the following:
uid, which holds an integer value
hash, which is a string
If it helps, I have another app built in Titanium framework which uses this syntax:
xhr.setRequestHeader('uid', userid);
xhr.setRequestHeader('hash', hash);
So, am basically looking for a Swift equivalent.

You are using dataTaskWithURL while you should use dataTaskWithRequest, that takes NSMutableURLRequest object as an input. Using this object you can set HTTP headers, HTTPBody, or HTTPMethod
let urlPath = "http://www.xxxxxxxx.com"
let url = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "GET" // make it post if you want
request.addValue("application/json", forHTTPHeaderField: "Content-Type")//This is just an example, put the Content-Type that suites you
//request.addValue(userid, forHTTPHeaderField: "uid")
//request.addValue(hash, forHTTPHeaderField: "hash")
let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
//do anything you want
})
task.resume()

I suggest you to use Alamofire for networking
https://github.com/Alamofire/Alamofire
It is written in Swift and is every easy to use. Have a look at that page.

Related

how can I fix this urlString error from returning nil

So my goal is to successfully send notifications to users subscribed to a specific topic with no errors. I have a function that I use to send notifications with FCM, here it is:
func sendNotificationToUser(to token: String, title: String, body: String) {
getTheSchoolID { (id) in
if let id = id {
let urlString = "https://fcm.googleapis.com/v1/projects/thenameofmyproject-41f12/messages:send HTTP/1.1"
let url = NSURL(string: urlString)!
let paramString: [String: Any] = ["message": ["topic": id,
"notification": ["title": title, "body": body],
"data": ["user": "test_id"]
]
]
let request = NSMutableURLRequest(url: url as URL)
request.httpMethod = "POST"
request.httpBody = try? JSONSerialization.data(withJSONObject: paramString, options: [.prettyPrinted])
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(self.bearer)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request as URLRequest) { (data, response, error) in
do {
if let jsonData = data {
if let jsonDataDictionary = try JSONSerialization.jsonObject(with: jsonData, options: JSONSerialization.ReadingOptions.allowFragments) as? [String: AnyObject] {
NSLog("Received data:\n\(jsonDataDictionary))")
}
}
} catch let err as NSError {
print(err.debugDescription)
}
}
task.resume()
}
}
}
I found this block of code originally off a Youtube video and tested it with my iPhone and it worked beautifully, but I modified it a bit to look like this and now when this function gets ran I get an error saying the urlString is producing a nil value.
I copied the format from the documentation and just switched out the project name, but for some reason I still get errors. Is there something wrong with url that I can't see? Also, in the image I shown below, should I add the "ya29." before my bearer key or is the value just fine how it is?
Not really sure what you are trying to do, you dont trigger notifications by calling APNS/fcm API directly from client apps, anyway question is why is URL is being nil, well you can avoid it being nil if you percentile encode the url string
let urlString = "https://fcm.googleapis.com/v1/projects/thenameofmyproject-41f12/messages:send HTTP/1.1"
guard let encodedURLString = urlString.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed) else { return }
let url = URL(string: encodedURLString)! //NSURL(string: encodedURLString)!
You dont need NSURL you can use URL instead.
Why percentile encode?
Because your url has a white space between send and HTTP send HTTP and white spaces are not allowed in valid url, if you want that white space to persist in your URL you should encode it. White space will be replaced by %20

JSON data extraction in swift

I am using the following code:
let string = "https://wordsapiv1.p.mashape.com/words/?
hasDetails=examples&page=1"
let url = NSURL(string: string)
let request = NSMutableURLRequest(url: url! as URL)
request.setValue("KEY", forHTTPHeaderField: "X-Mashape-Key")
request.httpMethod = "GET"
let session = URLSession.shared
let task = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
if let resp = response as? HTTPURLResponse {
let json = try? JSONSerialization.jsonObject(with: data!, options: [])
print(json)
}
}
task.resume()
And the following is printed by the 'print(json)' line of code:
Optional({
query = {
limit = 100;
page = 1;
};
results = {
data = (
".22 caliber",
".38 caliber",
a,
"a bit",
"a cappella",
"a couple of",
"a few",
"a great deal",
"a little",
"a lot",
"a posteriori",
"a priori",
"a trifle",
aah,
abacinate,
abaft,
abandon,
abandoned,
abandonment,
abasement,
abashed,
"abatable nuisance",
abate,
abatement,
abaxial,
abbreviated,
abdicable,
abdicate,
abdominal,
"abdominal breathing",
abduct,
aberrant,
aberrate,
abhor,
abhorrent,
"abide by",
abiding,
abject,
abjectly,
abjure,
ablated,
ablative,
ablaze,
able,
"able-bodied",
ablutionary,
abnegate,
abnegation,
abnormal,
abnormally,
aboard,
abolish,
abolition,
abominable,
abominably,
abomination,
aboral,
aboriginal,
abort,
abortive,
abound,
abounding,
about,
"about-face",
above,
"above all",
aboveboard,
aboveground,
abrasive,
abreast,
abridge,
abridged,
abroach,
abroad,
abrupt,
abscessed,
abscond,
abseil,
absence,
absent,
absently,
absentminded,
absolute,
absolutely,
absoluteness,
absolve,
absolved,
absorb,
absorbed,
absorbent,
absorptance,
absorption,
abstain,
abstemious,
abstemiously,
abstinent,
abstract,
abstractive,
abstruse,
abstrusely
);
total = 21753;
};
})
The problem is that I need to get just the data that I want from this i.e. the words.
How do I now get the data from this that I want? i.e. an array of all the words returned (from ".22 caliber" to abstrusely)
I like to use the SwiftyJson cocoapod, as its much easier to read and understand than JSONDecoder (but of course, that would work too):
import SwiftyJson
let string = "https://wordsapiv1.p.mashape.com/words/?hasDetails=examples&page=1"
let url = NSURL(string: string)
let request = NSMutableURLRequest(url: url! as URL)
request.setValue("KEY", forHTTPHeaderField: "X-Mashape-Key")
request.httpMethod = "GET"
let session = URLSession.shared
var wordArray : [String] = []
let task = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
if let resp = response as? HTTPURLResponse {
let json : JSON = JSON(data!)
for word in json["results"]["data"] { //There's probably a way to cast directly to a [String] here instead but I'm not sure.
wordArray.append(word)
}
}
}
task.resume()

How to POST data from multiple view controllers to server with JSON using SWIFT

I need help with combining data collected from firstVC, secondVC, and thirdVC and serializing those in the fourthVC.
This link helps with one VC but I have to send only ONE FILE of JSON DATA to the server.
How to create and send the json data to server using swift language
The other method is passing a dictionary array from firstVC, secondVC, and thirdVC to the fourthVC and from the fourthVC convert the dictionaries into JSON. But i don't know how to do that.
I used the format from the answer provided in the link above, but if you need additional info, I will gladly cooperate. Thanks!
PS. Please give me useful comments that will help in any way. I need the code and not feedbacks like doing my own research and such cause I have been stressing about this for nearly a month now.
This is the UserDefault keys
if let AC = UserDefaults.standard.value(forKey: "Acc") as? String {
labeltext.text = "\(AC)"
}
if let TY = UserDefaults.standard.value(forKey: "Taxyear") as? String {
taxtext.text = "\(TY)"
}
if let BB = UserDefaults.standard.value(forKey: "Bsb") as? String {
bsbtext.text = "\(BB)"
}
Here is my JSON code
#IBAction func save(_ sender: Any){
typealias JSONDictionary = [String:Any]
let parameters = ["BankAccountNumber": "Acc", "Tax Year": "Taxyear", "my-bsb": "Bsb"]
let url = URL(string: "https://server:port/")! //change the url
//create the session object
let session = URLSession.shared
//now create the URLRequest object using the url object
var request = URLRequest(url: url)
request.httpMethod = "POST" //set http method as POST
let valid = JSONSerialization.isValidJSONObject(parameters) // true
print (valid)
do {
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) // pass dictionary to nsdata object and set it as request body
} catch let error {
print(error)
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
// create dataTask using the session object to send data to the server
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
guard error == nil else {
return
}
guard let data = data else {
return
}
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
print(json)
// handle json...
}
} catch let error {
print(error.localizedDescription)
}
})
task.resume()
let alertMessage = UIAlertController(title: "Saved!", message: "We have recorded your information", preferredStyle: UIAlertControllerStyle.alert)
let action = UIAlertAction(title:"Okay", style: UIAlertActionStyle.default, handler: nil)
alertMessage.addAction(action)
self.present(alertMessage, animated: true, completion: nil)
}
I solved it by first storing them in a variable
var TITLE = UserDefaults.standard.value(forKey: "Title")
var GN = UserDefaults.standard.value(forKey: "GivenNames")
var LN = UserDefaults.standard.value(forKey: "LastName")
Then I placed them in a parameter and that's done. It was so obvious that I can't believe I didn't solve it sooner
#IBAction func save(_ sender: Any){
let parameters = ["Tax Year": TaxYear, "Title": TITLE, "first-name": GN, "sur-name": LN]

SwiftyJSON : How can I add token?

I'm using API and getting json data with SwiftyJSON. I need an add token for the API. How can I do this with SwiftyJson?
My code :
let jsonData = (NSData(contentsOfURL: NSURL(string: "http://api.football-data.org/v1/soccerseasons/424/leagueTable")!)! as NSData)
var readableJSON = JSON(data: jsonData, options: .MutableContainers, error: nil)
let name = readableJSON["standings"]
Normally I'm adding token with this code when I use Swift's JSON :
let url = NSMutableURLRequest(URL: NSURL(string: "http://api.football-data.org/v1/soccerseasons/424/leagueTable")!)
url.addValue("mytokenishere", forHTTPHeaderField: "X-Auth-Token")
url.HTTPMethod = "GET"
Are you making a post/put with this data? Thats would make sense.
I suppose you already have made the request to get the readable data "jsonData" contains that. Since you ndicate you dont have the json data already this would probably work.
var url = NSMutableURLRequest(URL: NSURL(string: "http://api.football-data.org/v1/soccerseasons/424/leagueTable")!)
url.addValue("mytokenishere", forHTTPHeaderField: "X-Auth-Token")
url.HTTPMethod = "GET"
NSURLSession.sharedSession().dataTaskWithRequest(url, completionHandler: data, response, error in {
if error == nil {
var readableJSON = JSON(data: data, options: .MutableContainers, error: nil)
let name = readableJSON["standings"]
url.HTTPBody = try! name.rawData()
NSURLSession.sharedSession().dataTaskWithRequest(url, completionHandler: data, response, error in {
//do something with his response from getting the data
})
} else {
print(error)
}
})
This is kind of a hacky way of doing it but I think its what you are going for

Parameters in JSON POST Request ignored in Swift?

I am trying to get some data from a URL which requires me to POST a JSON request. It works in the sense that I get some data back; just not the data I expected. I then used jsontest.com to test my code:
let url = NSURL(string: "http://echo.jsontest.com/")
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
do {
let params = ["echo": "abc"] as Dictionary<String, String>
//... Just make sure that 'params' is a valid JSON object
assert(NSJSONSerialization.isValidJSONObject(params))
request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(params, options: NSJSONWritingOptions.PrettyPrinted)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
} catch {
print("Error")
}
let session = NSURLSession.sharedSession()
dataTask = session.dataTaskWithRequest(request, completionHandler: {
(data: NSData?, response: NSURLResponse?, error: NSError?) in
if let httpResponse = response as? NSHTTPURLResponse where httpResponse.statusCode == 200,
let data = data {
let encodedData = NSString(data:data, encoding:NSUTF8StringEncoding)
print("encodedData = \(encodedData!)")
} else {
print("Error")
}
})
dataTask?.resume()
When I run this, I see the following output from jsontest.com:
encodedData = {"": ""}
where I expected
encodedData = {"echo": "abc"}
So, do I not understand correctly whether this is how jsontest.com works, or am I doing something wrong? (Obviously, I had similar problems using other JSON services.) Any comments are appreciated.
echo.jsontest.com doesn't work with a request body but with a request url, see www.jsontest.com/#echo for details.
Turns out #Eric D is right. I found another website to test my JSON posts on and that one worked fine. So the code is basically correct after all.
I made the following changes:
let url = NSURL(string: "http://gurujsonrpc.appspot.com/guru")
let params = [ "method" : "guru.test", "params" : [ "GB" ], "id" : 123 ] as Dictionary<String, AnyObject>
and then I get the following response:
{"jsonrpc":"2.0","id":123,"result":"Hello GB!"}
Which is exactly what was expected.
Thanks!
The correct URL is http://validate.jsontest.com
Also, I don't think you are constructing the POST request body correctly. See How are parameters sent in an HTTP POST request?