Mocking Alamofire interface to handle response cases in tests - ios

How can Alamofire calls such as request, download, upload be mocked so that one has control over the response and the flow in the callback?
I would like to test the response closures that Alamofire calls, without hitting the network. I would also like this to be self contained, without doing response rewrites with Charles.
It doesnt seem to be possible to mock certain Alamofire objects directly due to the internals and private methods etc.
Has anyone successfully managed to test these Alamofire response handlers?
E.g.
Alamofire.request("https://httpbin.org/get").responseJSON { response in
// using the mocked response here to control
// and assert execution flow inside this callback
}
Or
public func should(_ manager: SessionManager,
retry request: Request,
with error: Error,
completion: #escaping RequestRetryCompletion) {
// using the mocked request.task?.response here to control
// and assert execution flow inside this callback
}
I also cant seem to initialize any type of Alamofire Request (e.g. DataRequest) as compiler complains with DataRequest() and there are no initializers in the class.

Related

Is it normal that every HTTP request is executed twice using Alamofire? One without the authorization header and the other with it?

When I execute an HTTP request with an authorization token as a header, using Alamofire, the request is executed twice:
1) the first execution without the authorization, gets a 401 status code
2) the second with the authorization included, gets the expected 200
Is that normal or is that a bug?
If that is normal, could that be disabled? Is that recommended?
myNewRequest.headers["Authorization"] = token
SessionManager.default.request(newRequest)
.validate()
.response(queue: DispatchQueue.main) { _ in
// handle request
}

silex abort() on BootableProviderInterface ignores provided code, response has 200 always

I have a silex BootableProvider to check for some requirements on every request before executing calls to any of my end points. All works good, except that when I use the $app->abort('403', 'forbidden for some reason'); anywhere in the boot() method, the response always returns code 200. The 'forbidden' message is correctly displayed and execution is interrupted as expected fortunately, but not having a meaningful Status code on the response makes it hard/cumbersome to process these failure responses.
I'm using silex 2.0.4.
If i however, execute the $app->abort(...) from any of my endpoints which implement ControllerProviderInterface, in the same request thread, the responses have the correct response codes I specify in the abort, so I'm thinking it's a timing issue.
Any advise is greatly appreciated.
Sample Code:
class BootProvider implements BootableProviderInterface {
function boot(Application $app) {
$app->abort(403, 'not allowed');
}
}
...
$app->register(new My\Api\BootProvider());
I've tried passing headers to override the Status to no avail.
Thanks!
In you case you should get just exception Fatal error: Uncaught exception.... Service providers are booted before kernel handle cycle, so errors are not processed.
Try to add event listener or middleware that will be executed before controllers and will make all checks.
$app->before(function (Request $request, Application $app) {
$app->abort(403, 'not allowed');
});
http://silex.sensiolabs.org/doc/2.0/middlewares.html

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

What is the difference between the two request methods of alamofire?

I was just playing with Alamofire framework and making few api calls. However I observed there are two request methods in alamofire :
public func request(method: Method, URLString: URLStringConvertible, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL, headers: [String: String]? = nil) -> Request{...}
and
public func request(URLRequest: URLRequestConvertible) -> Request {...}
I found this really interesting, because the first method prototype is detailed and is easily understood. But the second one is quite confusing, I know that it takes a parameter which conforms to URLRequestConvertible protocol that is defined by Alamofire.
In the second request prototype the HTTP Method (GET or POST) that needs to be used is never specified, so how does the alamofire knows which HTTP method to be used. Is there a way to let alamofire know which http method to use while making request.
Also what are the other significant differences between these two methods (if any) and which one is preffered and why?
Thank you.
The rendition of request without a method or parameters is presuming that you manually prepared the NSMutableURLRequest that includes the appropriate HTTPMethod, the HTTP headers (e.g. Content-Type, etc.), and HTTPBody.
You wouldn't generally use this rendition of the request method (we use Alamofire precisely to get us out of the weeds of manually constructing requests), but is useful when you have to construct a request that Alamofire cannot otherwise prepare (e.g. Sending json array via Alamofire).

firefox addon-sdk : handle http request timeout

I'm building a firefox add-on using the add-on sdk. I need to make a http request to a certain page and I want to handle the connection timeout but couldn't find anything in the api: https://addons.mozilla.org/en-US/developers/docs/sdk/latest/modules/sdk/request.html
What I'm actually looking is a callback in case the client couldn't connect to the server.
Is there a way to achieve this?
The SDK request will always call onComplete, when the request is considered done for the network. This means that onComplete is called in any case, disregarding if the request returned an error or a success.
In order to detect which error you've got, you need to check the Response object's (the object passed to the onComplete function) property "status" (response.status). It holds the status code for the request. To look up status codes, consider the list on the mozilla developer network. If the response status is 0, the request has failed completely and the user is probably offline, or the target couldn't be reached.
A timeout would either be a status code 504 or 0. The implementation would be similar to this:
var Request = require("sdk/request");
Request({
url: "http://foo.bar/request.target",
onComplete: function(response) {
if(response.status==0||response.status==504) {
// do connection timeout handling
}
// probably check for other status codes
else {
// assume the request went well
}
}
}).get();
I personally use a validation function on the request object, which returns me a number which depends whether I've got a correct response, an error from the web server or a connection issue (4xx and 0 status codes).

Resources