Can not fetch data using Alamofire? - ios

I am trying to fetch data in my iOS app from my Django backend. In postman if I perform a GET request on the following URL http://127.0.0.1:8000/api/places/categories with the params being Key:"Authorization" Value: "Bearer access_token".I get a JSON response.
Inside my app I am doing something like this with the help of Alamofire:
let access_token = "123"
let headers = ["Authorization": "Bearer" + access_token]
Alamofire.request(self.categoriesUrl, method: .get, parameters:nil,encoding: JSONEncoding.default,headers: headers).response { response in
print("Request: \(response.request)")
print("Response: \(response.response)")
print("Error: \(response.error)")
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
print("Data: \(utf8Text)")
}
}
I get an error saying Authorization Credentials were not provided. I understand this and it asks me to pass in the parameters but the parameters just need a token. So I do something like this:
let access_token = "123"
let params = ["Authorization": "Bearer" + access_token]
Alamofire.request(self.categoriesUrl, method: .get, parameters:params,encoding: JSONEncoding.default,headers: nil).response { response in
print("Request: \(response.request)")
print("Response: \(response.response)")
print("Error: \(response.error)")
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
print("Data: \(utf8Text)")
}
}
It waits for a while but fails to fetch the data with the following error:
Response: nil
Error: Optional(Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={NSUnderlyingError=0x61800004b0d0 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=http://127.0.0.1:8000/api/places/categories/, NSErrorFailingURLKey=http://127.0.0.1:8000/api/places/categories/, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.})
Data:
EDIT1:

This is very simple to fix, I guess you are using iOS10 or later version of OS. So instead of calling http , just call https, which means the API calling protocol has been changed to http to https in iOS10 and later.

You have a typo here :
let params = ["Authorization": "Bearer" + access_token]
You're missing a space after Bearer.

Related

How to solve NSURLErrorDomain: Cannot decode raw data in swift

I am trying to send request to server. I get status code as 200, content-length is 90956 and result return
FAILURE: Error Domain=NSURLErrorDomain Code=-1015 "cannot decode raw data" in swift 4
I tried to change parameter encoding value as JSONEncoding.Default but nothing happen.
AF.request(url, method: .get, parameters: params, headers:headers)
.responseString { response in
print("Request :- " , response.request as Any)
print("Response error :- ", response.error as Any)
print("Response :- ", response.response as Any)
}
Actual
Data None
Network Duration: 0.06679093837738037s Duration: 2.5987625122070312e-05s
Result: FAILURE: Error Domain=NSURLErrorDomain Code=-1015 "cannot decode raw data"
Expected
Data: 90956 Network Duration: 0.06679093837738037s Duration: 2.5987625122070312e-05s Result: SUCCESS

Swift/iOS URL request to Node.js API endpoint

I have standard code in Swift like below:
private func testFormUrlEncodedRequest() {
let headers = [
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json"
]
let postData = NSMutableData(data: "user_id=5874ae8ae9a98c2d6cef1da8".data(using: String.Encoding.utf8)!)
postData.append("&offset=0".data(using: String.Encoding.utf8)!)
postData.append("&limit=20".data(using: String.Encoding.utf8)!)
let request = NSMutableURLRequest(url: NSURL(string: "http://www.example.com/endpoint")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data
ViewController.log(request: request as! URLRequest)
print((request as URLRequest).curlString)
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
ViewController.log(data: data, response: response as? HTTPURLResponse, error: error)
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()
}
But the problem is that it hangs on, and then request times out with error.
REST API is written in Node.js and gets error in body-parser module like request aborted.
I can make successfully the same request with POSTMAN or curl (from Terminal) and I get correct response.
Code on server which I have no access to seems to be also rather standard, and was used in previous projects where it was tested to work correctly with iOS apps.
I have no idea why this request goes ok with POSTMAN and doesn't work with URLSession in Swift.
Any help will be beneficial.
Here is error message printed to console I am getting:
Optional(Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={NSUnderlyingError=0x6000013196e0
{Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}},
NSErrorFailingURLStringKey=http://example.com/api/endpoint, NSErrorFailingURLKey=http://example.com/api/endpoint,
_kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.})
This request gives error in such cases:
1. form-url-encoded params in HTTP request body
2. raw application/json params in HTTP request body
3. It works if params are passed in query params
4. It crashes with request aborted error on server side (body-parser module)
5. node.js uses standard app.use()
// support parsing of application/json type post data
app.use(bodyParser.json());
//support parsing of application/x-www-form-urlencoded post data
app.use(bodyParser.urlencoded({ extended: true }));
It uses http without SSL but in Info.plist there is App Transport Security > Allow Arbitrary Loads set to YES etc.
UPDATE:
This is error on server side
BadRequestError: request aborted
at IncomingMessage.onAborted (/Users/michzio/Click5Interactive/Reusable Parts/NetworkApi/node_modules/raw-body/index.js:231:10)
at emitNone (events.js:86:13)
at IncomingMessage.emit (events.js:188:7)
at abortIncoming (_http_server.js:381:9)
at socketOnClose (_http_server.js:375:3)
at emitOne (events.js:101:20)
at Socket.emit (events.js:191:7)
at TCP.Socket._destroy.cb._handle.close [as _onclose] (net.js:510:12)
Node.js Test Code:
const express = require('express');
const port = 9001;
const app = express();
const bodyParser = require('body-parser');
var todos = [{id:1, title:'buy the milk'}, {id:2, title:'rent a car'}, {id:3, title:'feed the cat'}];
var count = todos.length;
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json());
app.get('/test', (request, response) => {
console.log("-----")
console.log(request.params);
console.log(request.body);
console.log(request.query);
console.log("-----")
response.status(200).json( todos );
});
app.listen(port);
It seems that GET + query params works, and POST + body params (url-from-encoded or application/json) also works correctly.
So it doesn't work for GET body params url-form encoded and GET body params application/json. Is it some limitation of URLSession/URLRequest in Swift. POSTMAN can pass params in body with GET and server receives it in request.body !
UPDATE 2!
Yes, it seems that in Android/Kotlin with OkHttpClient there even is not possible to define Request Body with GET method. And there is also this error. Maybe this only works with POSTMAN and curl, and should not be used in real application scenario to join GET and body params.
public fun makeNetworkRequest(v: View) {
object : Thread() {
override fun run() {
val client = OkHttpClient()
val mediaType = MediaType.parse("application/json")
val body = RequestBody.create(mediaType, "{ \"test\" : \"nowy\", \"test2\" : \"lol\" }")
/*
val request = Request.Builder()
.url("http://10.0.2.2:9001/test")
.get()
.addHeader("Content-Type", "application/json")
.build()
*/
val mySearchUrl = HttpUrl.Builder()
.scheme("http")
.host("10.0.2.2")
.port(9001)
.addPathSegment("test")
.addQueryParameter("q", "polar bears")
.build()
val request = Request.Builder()
.url(mySearchUrl)
.addHeader("Accept", "application/json")
.method("GET", body)
.build()
val response = client.newCall(request).execute()
Log.d("RESPONSE", response.toString())
}
}.start()
}

Alamofire post method in iOS Swift 4?

For getting push notification here i am sending postitem, token, like count and currentname using alamofire post method(pod version alamofire 4.5). I did not get any response when post method called and it does not show any errors.
I tried keeping breaking points in alamofire function, it call alamofire.requestion then it goes out function.
Here is the code tried to send post method to backend:
func postNotification(postItem: String, post: Post) {
print("Get token from post:::",post.token)
print(postItem)
let token = UserDefaults.standard.string(forKey: "token")
let headers: HTTPHeaders = ["Content-Type" :"application/x-www-form-urlencoded"]
let parameters : [String:Any] = ["count":post.likeCount!, "likedby":currentName, "postId=":postItem, "token": post.token!]
Alamofire.request("http://highavenue.co:9000/likesnotification/", method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: nil).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success(_):
if let data = response.result.value{
print(data)
}
break
case .failure(_):
print(response.result.error as Any)
break
}
}
}
Getting console error like this
2018-07-10 14:21:07.980212+0530 HighAvenue[10584:4236493] Task <B5FC98AB-C3FE-
4D4F-9A93-72D3FFE35DF7>.<1> finished with error - code: -1001
Optional(Error Domain=NSURLErrorDomain Code=-1001 "The request timed out."
UserInfo={NSUnderlyingError=0x1c0e478f0 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=http://highavenue.co:9000/likesnotification/, NSErrorFailingURLKey=http://highavenue.co:9000/likesnotification/, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.})
That is because you are not setting request time in your network call, by default your request time is a small interval, so please increase request timeout time. something like this,
let request = NSMutableURLRequest(url: URL(string: "")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.timeoutInterval = 120 // 120 secs
let values = ["key": "value"]
request.httpBody = try! JSONSerialization.data(withJSONObject: values, options: [])
Alamofire.request(request as! URLRequestConvertible).responseJSON {
response in
// do whatever you want here
}
Second mistake in your code is you are trying to access http url which are by default are not allowed so you have to by pass this security from your app, Please refer to this answer in order to remove this security layer from your app.
The resource could not be loaded because the App Transport Security policy requires the use of a secure connection

SoundCloud API: GET request fails with code -1005, using iOS/Alamofire

I'm working on an iOS app where SoundCloud users log in with OAuth in a web view and then the app makes HTTP requests to the SoundCloud API via Alamofire. I've successfully authenticated the user and stored their token (using ABMSoundCloudAPI), but GET requests to https://api.soundcloud.com/me are failing with a -1005 error, "The network connection was lost." This seems to be a common problem with iOS as discussed here, however resetting the simulator doesn't solve the problem for me and the problem also occurs when using a device. I've also tried:
Removing and re-adding the wifi network
Retrying the request programmatically if it fails
Adding a header with "Connection": "Close"
I see the same error in every case. Are there other headers I should try? I'm using these libraries via Cocoapods:
ABMSoundCloudAPI (0.2.1)
AFNetworking (2.6.1)
AFOAuth2Manager (2.2.0)
Alamofire (3.1.2)
SwiftyJSON (2.3.1)
Here is my code:
var retryCount = 0
func getUserInfo(token:String) {
let headers = ["Connection": "Close"]
Alamofire.request(.GET, "https://api.soundcloud.com/me?oauth_token=\(token)", parameters: ["client_id":clientId], encoding: .JSON, headers: headers)
.responseJSON { response in
guard response.result.error == nil else {
print("error calling GET on /me")
print(response.result.error)
if self.retryCount < 2 {
if let token = self.defaults.stringForKey("sc_key_token") {
self.getUserInfo(token)
++self.retryCount
}
}
return
}
guard let value = response.result.value else {
print("Error: did not receive data")
return
}
let user = JSON(value)
print("User info: " + user.description)
}
}
Error message:
Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo={NSUnderlyingError=0x126248c10 {Error Domain=kCFErrorDomainCFNetwork Code=-1005 "(null)" UserInfo={_kCFStreamErrorCodeKey=-4, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=https://api.soundcloud.com/me?oauth_token=USER_TOKEN, NSErrorFailingURLKey=https://api.soundcloud.com/me?oauth_token=USER_TOKEN, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-4, NSLocalizedDescription=The network connection was lost.}
It seems that this was caused by the request encoding. When I switched from .JSON to .URL, the 1005 error went away.

Alamofire invalid value around character 0

Alamofire.request(.GET, "url").authenticate(user: "", password: "").responseJSON() {
(request, response, json, error) in
println(error)
println(json)
}
This is my request with Alamofire, for a certain request it sometime works, but sometimes i get:
Optional(Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (Invalid value around character 0.) UserInfo=0x78e74b80 {NSDebugDescription=Invalid value around character 0.})
I've read that this can be due to invalid JSON, but the response is a static json string that i have validated in JSON validator as valid. It does contain å ä ö characters and some HTML.
Why am i getting this error sometimes?
I also faced same issue. I tried responseString instead of responseJSON and it worked. I guess this is a bug in Alamofire with using it with django.
In my case , my server URL was incorrect. Check your server URL !!
I got same error while uploading image in multipart form in Alamofire as i was using
multipartFormData.appendBodyPart(data: image1Data, name: "file")
i fixed by replacing by
multipartFormData.appendBodyPart(data: image1Data, name: "file", fileName: "myImage.png", mimeType: "image/png")
Hope this help someone.
May this Help YOu
Alamofire.request(.GET, "YOUR_URL")
.validate()
.responseString { response in
print("Success: \(response.result.isSuccess)")
print("Response String: \(response.result.value)")
}
The same issue happened to me and it actually ended up being a server issue since the content type wasn't set.
Adding
.validate(contentType: ["application/json"])
To the request chain solved it for me
Alamofire.request(.GET, "url")
.validate(contentType: ["application/json"])
.authenticate(user: "", password: "")
.responseJSON() { response in
switch response.result {
case .Success:
print("It worked!")
print(response.result.value)
case .Failure(let error):
print(error)
}
}
I got the same error. But i found the solution for it.
NOTE 1: "It is not Alarmofire error", it's bcouse of server error.
NOTE 2: You don't need to change "responseJSON" to "responseString".
public func fetchDataFromServerUsingXWWWFormUrlencoded(parameter:NSDictionary, completionHandler: #escaping (_ result:NSDictionary) -> Void) -> Void {
let headers = ["Content-Type": "application/x-www-form-urlencoded"]
let completeURL = "http://the_complete_url_here"
Alamofire.request(completeURL, method: .post, parameters: (parameter as! Parameters), encoding: URLEncoding.default, headers: headers).responseJSON { response in
if let JSON = response.result.value {
print("JSON: \(JSON)") // your JSONResponse result
completionHandler(JSON as! NSDictionary)
}
else {
print(response.result.error!)
}
}
}
This is how I managed to resolve the Invalid 3840 Err.
The error log
responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}))
It was with Encoding Type used in the Request, The Encoding Type used should be acceptedin your Server-Side.
In-order to know the Encoding I had to run through all the Encoding Types:
default/
methodDependent/
queryString/
httpBody
let headers: HTTPHeaders = [
"Authorization": "Info XXX",
"Accept": "application/json",
"Content-Type" :"application/json"
]
let parameters:Parameters = [
"items": [
"item1" : value,
"item2": value,
"item3" : value
]
]
Alamofire.request("URL",method: .post, parameters: parameters,encoding:URLEncoding.queryString, headers: headers).responseJSON { response in
debugPrint(response)
}
It also depends upon the response we are recieving use the appropriate
responseString
responseJSON
responseData
If the response is not a JSON & just string in response use responseString
Example: in-case of login/ create token API :
"20dsoqs0287349y4ka85u6f24gmr6pah"
responseString
I solved using this as header:
let header = ["Content-Type": "application/json",
"accept": "application/json"]
In my case, there was an extra / in the URL .
Maybe it is too late but I solved this problem in another way not mentioned here:
When you use .responseJSON(), you must set the response header with content-type = application/json, if not, it'll crash even if your body is a valid JSON. So, maybe your response header are empty or using another content-type.
Make sure your response header is set with content-type = application/json to .responseJSON() in Alamofire work properly.
Hey guys this is what I found to be my issue: I was calling Alamofire via a function to Authenticate Users: I used the function "Login User" With the parameters that would be called from the "body"(email: String, password: String) That would be passed
my errr was exactly:
optional(alamofire.aferror.responseserializationfailed(alamofire.aferror.responseserializationfailurereason.jsonserializationfailed(error domain=nscocoaerrordomain code=3840 "invalid value around character 0." userinfo={nsdebugdescription=invalid value around character 0
character 0 is the key here: meaning the the call for the "email" was not matching the parameters: See the code below
func loginUser(email: String, password: String, completed: #escaping downloadComplete) {
let lowerCasedEmail = email.lowercased()
let header = [
"Content-Type" : "application/json; charset=utf-8"
]
let body: [String: Any] = [
"email": lowerCasedEmail,
"password": password
]
Alamofire.request(LOGIN_USER, method: .post, parameters: body, encoding: JSONEncoding.default, headers: header).responseJSON { (response) in
if response.result.error == nil {
if let data = response.result.value as? Dictionary<String, AnyObject> {
if let email = data["user"] as? String {
self.userEmail = email
print(self.userEmail)
}
if let token = data["token"] as? String {
self.token_Key = token
print(self.token_Key)
}
"email" in function parameters must match the let "email" when parsing then it will work..I no longer got the error...And character 0 was the "email" in the "body" parameter for the Alamofire request:
Hope this helps
I was sending the improper type (String) to the server in my parameters (needed to be an Int).
Error was resolved after adding encoding: JSONEncoding.default with Alamofire.
Alamofire.request(urlString, method: .post, parameters:
parameters,encoding:
JSONEncoding.default, headers: nil).responseJSON {
response in
switch response.result {
case .success:
print(response)
break
case .failure(let error):
print(error)
}
}
The application I was working on this morning had the same error. I believed it to be a server side error since I was unable to upload a user image.
However, upon checking my custom API, I realized that after adding an SSL certificate to my website that I had not updated the api.swift URLs, the data was unable to post:
let HOME_URL = "http://sitename.io"
let BASE_URL = "http://sitename.io/api"
let UPLOAD_URL = "http://sitename.io/api/user/upload"
I changed the URL's to https://. Problem solved.
In my case I have to add this Key: "Accept":"application/json" to my header request.
Something like this:
let Auth_header: [String:String] = ["Accept":"application/json", "Content-Type" : "application/json", "Authorization":"Bearer MyToken"]
I hope that this can help someone.
I face same issue and problem is in params.
let params = [kService: service,
kUserPath: companyModal.directory_path,
kCompanyDomain: UserDefaults.companyDomain,
kImageObject: imageString,
kEntryArray: jsonString,
kUserToken: UserDefaults.authToken] as [String : Any]
companyModal.directory_path is url. it coerced from string to any which create issues at server side. To resolve this issue I have to give default value which make it string value.
let params = [kService: kGetSingleEntry,
kUserPath: companyModal.directory_path ?? "",
kCompanyDomain: UserDefaults.companyDomain,
kUserToken: UserDefaults.authToken,
kEntryId: id,
] as [String: Any]
Probably you have "/" at the end of your path. If it is not GET request, you shouldn't put "/" at the end, otherwise you'll get the error
I Changed mimeType from "mov" to "multipart/form-data".
Alamofire.upload(multipartFormData: { (multipartFormData) in
do {
let data = try Data(contentsOf: videoUrl, options: .mappedIfSafe)
let fileName = String(format: "ios-video_%#.mov ", profileID)
multipartFormData.append(data, withName: "video", fileName: fileName, mimeType: "multipart/form-data")
} catch {
completion("Error")
}
}, usingThreshold: .init(), to: url,
method: .put,
headers: header)
Worked for me.. :)
For my case:
let header = ["Authorization": "Bearer \(Authserices.instance.tokenid)"]
I forgot the space before \ (after Bearer)
In my case error was due to duplicate email. You can recheck your API on postman to see if response there is OK or not.
In my case, I tried using Postman to get API and this error come from backend.

Resources