How to call REST API deployed in AWS on iOS app? - ios

I am new to AWS and trying to implement a webservice API GET call on iOS app. So following is the postman I have and trying to implement the same in iOS app;
But I am confused in setting this header on URLSession requests. I am not seeing much documentations regarding this. Looking forward for some help in implementing this on iOS app.
Tried to implement the Swift code generated in Postman :
But this implementation returns a Forbidden error message , so i believe some different implementation is needed to connect AWS

Can you show us what you have tried with URLSession so far ?
As said by #burnsi, you show look at the raw headers that are working for you in Postman and try to replicate those.
Some headers should always be used for all requests (given a particular URLSession), so you should consider configuring your session using httpAdditionalHeaders:
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = [
"Accept-Encoding": "application/json",
"Content-Type": "application/json"
]
let session: URLSession = URLSession(configuration: configuration)
For headers that are request-specific or likely to change over time (like an authorization token), you should add them to the request itself using setValue(_:forHTTPHeaderField:):
var request: URLRequest = URLRequest(url: url)
request.setValue("XYZ", forHTTPHeaderField: "Authorization")
Then you should perform the request using:
session.dataTask(with: request, completionHandler: { (data, response, error) in
print("Data: \(data?.debugDescription)\nResponse: \(response?.debugDescription)\nError: \(error?.debugDescription)")
})
Let us know what this code prints out for you and I'll try to help more!

Related

Alamofire request fails with nil response

I am getting numerous failed requests with Alamofire 5.3, where the response object itself is nil, or the error is "cannot parse response". I can see from the server logs that all of those requests are returning valid.
Here is my setup:
API manager class:
let config = Alamofire.Session.default.session.configuration
self.session = Alamofire.Session(configuration: config, interceptor: AccessTokenInterceptor())
AccessTokenInterceptor:
class AccessTokenInterceptor: RequestInterceptor {
func adapt(_ urlRequest: URLRequest, for session: Alamofire.Session, completion: #escaping (AdapterResult<URLRequest>) -> Void) {
var adaptedRequest = urlRequest
adaptedRequest.setValue("application/json", forHTTPHeaderField: "Accept")
adaptedRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
if let token = SettingsManager.shared.userToken {
adaptedRequest.setValue("Bearer " + token, forHTTPHeaderField: "Authorization")
}
completion(.success(adaptedRequest))
}
}
This interceptor inserts my auth token from SettingsManager
I am also using the standard router for URLRequestConvertible where encoding is done by JSON serialization (dictionary) or Codable protocol (objects)
case .login(let body):
request.httpBody = try JSONSerialization.data(withJSONObject: body, options: [])
case .register(let object):
request.httpBody = try JSONEncoder().encode(object)
What is strange is that I don't think I'm doing anything different from the many other times I've used Alamofire and now the first request I make fails but the following one succeeds. If I remove the interceptor, there is no change.
If I inspect the outgoing headers or body content, it all seems normal, but the response from Alamofire is nil.
UPDATE: By using OS_ACTIVITY_MODE and iOS 13 I was able to see that it was complaining about the request headers and protocol. The server is on Elastic Beanstalk so I've been trying to mess with the SSL policy but still the first request fails every time.
This turned into quite the rabbit hole, so in the interest of community improvement, here is what I found.
After searching through the activity log errors, I noticed that iOS was complaining about an invalid header type -- upgrade. Searching for that value I found this question about removing the header. I learned that Apache acts as a proxy on Elastic Beanstalk but there is a mix up for HTTP/2 headers in the request, and iOS does not like that.
To get away from the header value, I ended up switching to Nginx proxy. Since my application uses Laravel, I then needed to deal with correcting the pretty URLs. To do that I found this answer. Now my web and mobile application both seem to be getting along nicely.

How to implement Vision API with 'Service account' in the iOS app?

I'm trying to implement Google Vision API for the my app via REST.
https://cloud.google.com/vision/docs/pdf
Is there any examples or any suggestions how to do this?
Documentation says that they require service account token but can't find any examples how to get service account token from iOS app side.
I've tried via GTMAppAuth but getting 403 error
I was able to generate this token from my mac machine and all worked, but token has limited life time and after 3-4 hours it expiries
I figured out and did this by my own.
Documentation:
https://developers.google.com/identity/protocols/OAuth2ServiceAccount#jwt-auth
1)You need to create service account, download p12 or JSON file. JSON file contains private key and public certificate url. You need to create text file, where private key on the top, certificate on the bottom and run this command:
openssl pkcs12 -export -in file_name.txt -out file_name.p12
2)Create jwt token with parameters which described in the documentation (for jwt I used this library: https://github.com/yourkarma/JWT)
3) Make POST request to https://www.googleapis.com/oauth2/v4/token with parameters which described in the documentation
Hope it will help somebody in the future
First you need to get a Bearer Token... You can get it by following the instructions on this page...
https://cloud.google.com/vision/docs/auth#using_an_api_key
The Bearer Token will not expire, you can implemented it to your code...
A Basic Version on how to add a Bearer Token to your Request in Swift is Shown below... All other Stuff goes as a JSON in Data Format to the "body" parameter
This Link will show you how to build up the JSON for your request to Vision... https://cloud.google.com/vision/docs/using-curl
class APIHandler {
private let API_TOKEN = "Your Token"
func requestVisionFromREST(body: Data, completion: #escaping (_ response: Data?)-> Void) {
let config = URLSessionConfiguration.default
var headers = [String:String]()
headers["Authorization"] = "Bearer \(API_TOKEN)"
config.httpAdditionalHeaders = headers
var urlRequest = URLRequest(url: URL(string: "YOUR URL")!)
urlRequest.httpMethod = "POST"
urlRequest.httpBody = body
URLSession(configuration: config).dataTask(with: urlRequest) { (data, response, error) in
completion(data)
}.resume()
}
}
EDIT
If you want to use the Google Sign In instead of the OAuth Method, to reauth your apps and get a fresh token, you can follow the instructions on the googles instructions page below:
https://developers.google.com/identity/sign-in/ios/offline-access

set Http Headers for all subsequent url calls in web view iOS + Swift 3

I am trying to load a URL in a web-view. I have to set the Http Headers for the url dynamically. For the first url load request the http headers is set properly but I don't think the headers is set for the subsequent web-veiw calls. Any one please let me know how to pass the http headers for all subsequent web view calls.
var webUrl = "https://example.com"
let request = NSMutableURLRequest(url: NSURL(string:WebUrl)! as URL)
request.setValue("xxxxxxxx",forHTTPHeaderField:"Authorization")
webView.loadRequest(request as URLRequest)
Thanks in advance .
https://github.com/yarshure/NSURLProtocolExample
The above example allowed me to intercept all the request made by webview so that I can add the HTTP headers.

NSURLSession treats http url as https, only on some devices

I have an app running on a test server that doesn't support https. I added the ATS exceptions in the info.plist and it worked well on the devices I tested on.
Now some of my test flight users started complaining about the app not being able to connect to the server. One of the devices in my office started having this problem too, so I had the change to look into it.
I am making a server request like this:
let path = "http://myurl.com"
let request = NSMutableURLRequest(URL: NSURL(string: path)!)
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
let httpResponse = response as? NSHTTPURLResponse
print(httpResponse)
print(NSString.init(data: data!, encoding: NSUTF8StringEncoding)!)
})
task.resume()
Now when I look at the URL from the NSHTTPURLResponse it is printed as "https://myurl.com". Somehow it just added the 's' to it. This only happens on some devices, I can't seem to find a pattern.
When I open the https url in a browser I get redirected to some other project we're working on. When I look at the response data that's exactly what I see. So somehow on some devices when you enter a http url it just converts it to https or something...
So far it's only been on iOS9 devices, but that may very well be a coincidence. Does anyone have an idea why this happens and what to do about it?

Does Alamofire store the cookies automatically?

I'm new to Alamofire so I'm sorry if this it's a noob question: this framework stores the cookies automatically?
This is because I have a simple request like this:
Alamofire.request(.POST, loginURL, parameters: ["fb_id": fbId, "fb_access_token": fbToken])
.responseJSON { response in
//print(response.request) // original URL request
//print(response.response) // URL response
//print(response.data) // server data
//print(response.result) // result of response serialization
if let JSON = response.result.value {
print("loginURL - JSON: \(JSON)")
}
}
this request response with a cookie session that I need to do other requests for security reason; the strange thing is that like magic I already can do the other requests after this first POST without read manually the cookie and store it. I'm sure the other requests need the cookie session because they fail on postman for example but not here.
It's just a feature? Because I can't find anything on that also on the official GitHub page.
Yes! Alamofire is basically a wrapper around NSURLSession. Its manager uses a default NSURLSessionConfiguration by calling defaultSessionConfiguration().
As its github page says under Advanced Usage section:
Alamofire is built on NSURLSession and the Foundation URL Loading System. To make the most of this framework, it is recommended that you be familiar with the concepts and capabilities of the underlying networking stack.
And under Manager section:
Top-level convenience methods like Alamofire.request use a shared instance of Alamofire.Manager, which is configured with the default NSURLSessionConfiguration.
And the NSURLSessionConfiguration reference for defaultSessionConfiguration() says:
The default session configuration uses a persistent disk-based cache (except when the result is downloaded to a file) and stores credentials in the user’s keychain. It also stores cookies (by default) in the same shared cookie store as the NSURLConnection and NSURLDownload classes.
For those who use Moya and want to disable stored cookies
(fixing the X-CSRF-Token request header is missing)
Very basic example:
public final class DisableCookiePlugin: PluginType {
public init() {
}
public func prepare(_ request: URLRequest, target: TargetType) -> URLRequest {
var mutableRequest = request
mutableRequest.httpShouldHandleCookies = false
return mutableRequest
}
}
And then use it
MoyaProvider<Api>(
plugins: [
//NetworkLoggerPlugin(configuration: .init(logOptions: .verbose)),
DisableCookiePlugin()
]

Resources