HTTP POST request in Swift - swift

How do I post the request on iOS? Actually when I logged into Facebook it fetches the user informations like username, from where there are login (latitude, longitude). Is it possible to use api
Link: http://buddysin.aumkiiyo.com/fbc
My code is:
#IBAction func btnAPI(sender: UIButton)
{
//startConnection()
connectToWebAPI()
}
func connectToWebAPI()
{
//setting up the base64-encoded credentials
let id = "1620912344817986"
//let password = "pass"
let loginString = NSString(format: "%#:%#", id)
let loginData: NSData = loginString.dataUsingEncoding(NSUTF8StringEncoding)!
let base64LoginString = loginData.base64EncodedStringWithOptions(nil)
//creating the requestz
let url = NSURL(string: "http://buddysin.aumkiiyo.com/fbc")
var request = NSMutableURLRequest(URL: url!)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession.sharedSession()
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let urlConnection = NSURLConnection(request: request, delegate: self)
request.HTTPMethod = "POST"
request.setValue(base64LoginString, forHTTPHeaderField: "Authorization")
let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
if (error != nil) {
println(error)
}
else {
// converting the data into Dictionary
var error: NSError?
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &error) as! NSDictionary
println(jsonResult)
}
})
//fire off the request
task.resume()
}
while I run, the fatal error where displayed as
`fatal error: unexpectedly found nil while unwrapping an Optional value`
in the "jsonResult"

i think it is better to use Alomafire. As AFNetWorking in Objective-C it is a library which simplified a lot http request.

Visit this question to check for my post-request function (if
you don't want to use Alamofire for any reasons)
Visit this question to check for steps you need to do if you
want to add Alamofire to your XCode-project
If you need to get json-data from your server, use
SwiftyJSON. It's as simple as dragging SwiftyJSON.swift into
your project with checking "Copy items if needed" and using like
let jsonData = JSON(data: yourDataFromServer)
Also you can view this question to check out for steps to encode
json-post data to send it to server.
Hope I helped :)

You should find which varible due to this error:
for example data,
if let dataTemp = data as? NSDictionary {
}
FYI:
Here is a way of 'POST' method of AFNetworking in swift, below code should be in your connectToWebAPI method, wrap your url ready into NSURL.
let manager = AFHTTPRequestOperationManager(baseURL: NSURL(string: yourURL))
manager.POST("path", parameters: ["key":value], success: { (opeartion:AFHTTPRequestOperation!, data:AnyObject!) -> Void in
},failure: { (operation:AFHTTPRequestOperation!, error:NSError!) -> Void in
})
Tutorial to install AFNetworking.
https://github.com/AFNetworking/AFNetworking/wiki/Getting-Started-with-AFNetworking

It is quite easy to do with Alamofire
func postSomething(completionHandler: #escaping CompletionHandler){
let loginString = NSString(format: "%#:%#", id)
let loginData: NSData = loginString.dataUsingEncoding(NSUTF8StringEncoding)!
let base64LoginString = loginData.base64EncodedStringWithOptions(nil)
let headers: HTTPHeaders = [
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "base64LoginString",
]
let parameters: Parameters = [
"parameter": value,
"parameter2": value2
]
Alamofire.request("http://buddysin.aumkiiyo.com/fbc", method: .post, parameters: parameters, encoding: URLEncoding.default, headers: SFAppServicesManager.sharedInstance.genericHeader()).responseJSON { response in
if let JSON = response.result.value {
let userDictionary = JSON as! NSDictionary
completionHandler(true)
} else {
completionHandler(false)
}
}
}

Related

Swift 'Required String parameter 'grant_type' is not present' error when trying to get an access token

So I'm trying to make an app in Swift for which I need to login to the OAuth to retrieve an access token. The API takes the parameters 'grant_type' and 'code'.
I've tried:
let params = ["grant_type":"authorization_code", "code":"123456789"] as Dictionary<String, String>
var request = URLRequest(url: URL(string: "https://myschool.zportal.nl/api/v3/oauth/token")!)
request.httpMethod = "POST"
request.httpBody = try? JSONSerialization.data(withJSONObject: params, options: [])
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let session = URLSession.shared
let task = session.dataTask(with: request, completionHandler: { data, response, error -> Void in
do {
let json = try JSONSerialization.jsonObject(with: data!) as! Dictionary<String, AnyObject>
print(json)
} catch {
print("error")
}
})
task.resume()
This returns:
["response": {
data = (
);
details = "class org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'grant_type' is not present";
endRow = 0;
eventId = 216795;
message = "Internal problems.";
startRow = 0;
status = 500;
totalRows = 0;
}]
This is weird, because I did parse the 'grant_type' parameter, and as the correct value.
It should return something like:
{
"response": {
"status":200,
"message":"",
"startRow":0,
"endRow":27,
"totalRows":27,
"data":[
{
},
...
]
}
}
The standard message format requires a Form URL Encoded body, not a JSON one. Maybe adapt your code as in this Swift article.
Got it working:
#IBAction func sendButtonPressed(_ sender: UIButton) {
let urlString = "https://myschool.zportal.nl/api/v3/oauth/token"
performRequest(urlString: urlString)
}
func performRequest(urlString: String) {
if let url = URL(string: urlString) {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = "grant_type=authorization_code&code=1234567890".data(using: .utf8)
let session = URLSession(configuration: .default)
let task = session.dataTask(with: request, completionHandler: { data, response, error -> Void in
//print(response!)
do {
let json = try JSONSerialization.jsonObject(with: data!) as! Dictionary<String, AnyObject>
print(json)
} catch {
print("error")
}
})
task.resume()
}
}
Not the nicest code but I'll polish it later.
At first I parsed JSON but it turned out I needed to parse a String and turn it into a Data type using: .data(using: .utf8)

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

Call Rest API from Swift3

I trying to send a POST request in swift for example :
url = "http://localhost:9080/mfp/api/az/v1/token"
Headers :
Authorization = "Basic UGlua0NhclBhc3NlbmdlcjoxMjM0"
Content-Type = "application/x-www-form-urlencoded"
Body :
grant_type = client_credentials
scope = RegisteredClient messages.write push.application.com.XXX
What's simple way to do it ?
I've tried by use IBMMobileFirstPlatformFoundation SDK, it's return error "Can't not connect to server",but i'm sure that the connect still good... Here's my code :
let urlString = "http://localhost:9080/mfp/api/az/v1/token"
let url1 = URL(string: urlString)
let request1 = WLResourceRequest(url: url1! as URL, method: WLHttpMethodPost)!
request1.addHeaderValue("Basic UGlua0NhclBhc3NlbmdlcjoxMjM0" as NSObject, forName: "Authorization")
request1.addHeaderValue("application/x-www-form-urlencoded" as NSObject, forName: "Content-Type")
request1.send(withBody: "{\"grant_type\":\"client_credentials\",\"scope\":\"RegisteredClient messages.write push.application.com.XXX\"}", completionHandler: { (response, error) in
if error == nil {
print("Response : ")
print(response)
} else {
print("Error : ")
print(error)
}
})
You can use Alamofire as ZassX suggested or you can use URLSession.
I have some code as an example:
func postRequest(toUrl url: String, accessKey: String?, completion: #escaping(Data?, HTTPURLResponse?, Error?, AnyObject?) -> Void){
let requestUrl = NSURL(string: url)
let request = NSMutableURLRequest(url: requestUrl! as URL)
if accessKey != nil {
request.setValue("\(accessKey!)", forHTTPHeaderField: "Authorization")
}
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
request.httpBody = yourBody
URLSession.shared.dataTask(with: request as URLRequest, completionHandler: { (data,response,error) in
if let content = data{
do{
let myJSON = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
completion(data as Data?, response as? HTTPURLResponse, error, myJSON)
}
catch{
print("JSON ERROR")
}
}else{
completion(data as Data?, response as? HTTPURLResponse, error, nil)
}
}).resume()
}
First, you don't manually manage the security token when you're using the MobileFirst SDK, it's handled automatically.
Next, WLResourceRequest() takes a URL that is relative to the MobileFirst server URL (http://localhost:9080/mfp, in your case). You can see that "base" URL in your mfpclient.plist file.
Your code will then look something like
let request = WLResourceRequest(
URL: NSURL(string: "/adapters/MyAdapter/myResource"),
method: WLHttpMethodGet
)
See https://mobilefirstplatform.ibmcloud.com/tutorials/en/foundation/8.0/application-development/resource-request/ios/

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

How to read response cookies using Alamofire

I am trying to read the response cookies for a post request, as done by Postman below
The way I am trying without success right now is
var cfg = NSURLSessionConfiguration.defaultSessionConfiguration()
var cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage()
cfg.HTTPCookieStorage = cookies
cfg.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicy.Always
var mgr = Alamofire.Manager(configuration: cfg)
mgr.request(.POST, "http://example.com/LoginLocalClient", parameters: parameters).responseJSON { response in
print(response.response!.allHeaderFields)
print(NSHTTPCookieStorage.sharedHTTPCookieStorage().cookies)
}
The first print statement contains the 10 header fields without the cookies, the second one contains an empty array.
Any ideas?
You need to extract the cookies from the response using the NSHTTPCookie cookiesWithResponseHeaderFields(_:forURL:) method. Here's a quick example:
func fetchTheCookies() {
let parameters: [String: AnyObject] = [:]
Alamofire.request(.POST, "http://example.com/LoginLocalClient", parameters: parameters).responseJSON { response in
if let
headerFields = response.response?.allHeaderFields as? [String: String],
URL = response.request?.URL
{
let cookies = NSHTTPCookie.cookiesWithResponseHeaderFields(headerFields, forURL: URL)
print(cookies)
}
}
}
Swift 5
func fetchTheCookies() {
let parameters: [String: AnyObject] = [:]
Alamofire.request(.POST, "http://example.com/LoginLocalClient", parameters: parameters).responseJSON { response in
if let headerFields = response.response?.allHeaderFields as? [String: String], let URL = response.request?.url
{
let cookies = HTTPCookie.cookies(withResponseHeaderFields: headerFields, for: URL)
print(cookies)
}
}
}
All the configuration customization you are attempting to do won't have any affect. The values you have set are already all the defaults.
Please be advised that the accepted answer does not work if the cookies are not posted within the header response. Apparently, some cookies are extracted in advance and stored in the shared cookie store and will not appear with the response.
You must use HTTPCookieStorage.shared.cookies instead.
Swift 3:
Alamofire.request(url, method: HTTPMethod.post, parameters: parameters).responseData { (responseObject) -> Void in
if let responseStatus = responseObject.response?.statusCode {
if responseStatus != 200 {
// error
} else {
// view all cookies
print(HTTPCookieStorage.shared.cookies!)
}
}
}
Credit goes to Travis M.
If you just want to read all the cookies against the domain you are interacting with, you can get all cookies with this method.
let cookies = Alamofire.Manager.sharedInstance.session.configuration.HTTPCookieStorage?.cookiesForURL(NSURL(string: "mydomain.com")! )
It returns an optional array of NSHTTPCookie items. (Swift 2.2 and Alamofire 3.4)
Swift 4.1:
let cookies = Alamofire.SessionManager.default.session.configuration.httpCookieStorage?.cookies(for: url)
the above code was correct I have used in this way -
var allCookies: [NSHTTPCookie]?
if let headerFields = aResponse.response?.allHeaderFields as? [String: String],
URL = aResponse.request?.URL {
allCookies = NSHTTPCookie.cookiesWithResponseHeaderFields(headerFields, forURL: URL)
for cookie in allCookies! {
print(cookie)
let name = cookie.name
if name == "nmSession" {
let value = cookie.value
print(value)
}
}
}
#lespommes
This is the only way I have received cookies. Now I can finally see Set-Cookie in a response:
let parameters = ["postLogin": ["login": "mymail#gmail.com", "password": "myPassword"]]
let url = NSURL(string: "your-website-with-cookies.com")
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(parameters, options: [])
Alamofire.request(request)
.responseJSON { response in
debugPrint(response)
if response.result.isSuccess {
...
}
}else if (response.result.isFailure){
...
}
}