I'm working with Alamofire. Following up on Mattt's comment in one of the closed issues on GitHub, I attempted a NSURLProtocol-based mechanism to set the UIApplication.sharedApplication().networkActivityIndicatorVisible flag.
However, after registering my custom protocol with Alamofire's underlying NSURLSessionConfiguration I got stuck pretty quickly since Alamofire doesn't expose much of its SessionDelegate class.
Is there a simple way to notify the custom NSURLProtocol the request has completed without reproducing much of the already existing implementation of Alamofire inside my NSURLProtocol?
A different way of doing it (not implementing NSURLProtocol-way) would be creating an API which would have an executeRequest method:
func executeRequest(method: Alamofire.Method, url: NSURL, parameters: [String: String]?, headers: [String : String]?) {
// Show activity indicator on status bar
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
let request = manager.request(method, url, parameters: parameters, encoding: .JSON, headers: headers)
.responseJSON {
response in
...
// Hide activity indicator on status bar
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
}
}
Of course, all your requests would have to be executed using the newly created API.
Related
I'm trying to update my app to Alamofire 5 and having difficulties due to a hack-ish way I'm using it I guess.
Anyhow, I need background uploads and Alamofire is not really designed to do this. Even so, I was using it to create a properly formatted file containing multipart form so I can give it to the OS to upload in the background later.
I'll post the code doing this in Alamofire 4, my question is how can I get the url of the file I was previously getting with encodingResults?
// We're not actually going to upload photo via alamofire. It does not offer support for background uploads.
// Still we can use it to create a request and more importantly properly formatted file containing multipart form
Api.alamofire.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(imageData, withName: "photo[image]", fileName: filename, mimeType: "image/jpg")
},
to: "http://", // if we give it a real url sometimes alamofire will attempt the first upload. I don't want to let it get to our servers but it fails if I feed it ""
usingThreshold: UInt64(0), // force alamofire to always write to file no matter how small the payload is
method: .post,
headers: Api.requestHeaders,
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let alamofireUploadTask, _, let url):
alamofireUploadTask.suspend()
defer { alamofireUploadTask.cancel() }
if let alamofireUploadFileUrl = url {
// we want to own the multipart file to avoid alamofire deleting it when we tell it to cancel its task
let fileUrl = ourFileUrl
do {
try FileManager.default.copyItem(at: alamofireUploadFileUrl, to: fileUrl)
// use the file we just created for a background upload
} catch {
}
}
case .failure:
// alamofire failed to encode the request file for some reason
}
}
)
Multipart encoding is fully integrated into the now-asynchronous request pipeline in Alamofire 5. That means there's no separate step to use. However, you can use the MultipartFormData type directly, just like you would in the request closure.
let data = MultipartFormData()
data.append(Data(), withName: "dataName")
try data.encode()
I was migrating my code to Swift 3 and updated Alamofire to the swift 3 branch.
There, the suggested way of handling parameter encoding is to use one of the new ParameterEncoding conforming structs, such as URLEncoding, that has an encode method.
The problem is that this method now throws, which makes sense, but the URLRequestConvertible protocol still expects a urlRequest property that returns the constructed request, so we can't just call encode and return the result, nor return a nil.
What is the suggested way of handling this, if the router can't fail?
That's how Alamofire handles it internally :
open func request(
_ urlString: URLStringConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: [String: String]? = nil)
-> DataRequest
{
let urlRequest = URLRequest(urlString: urlString, method: method, headers: headers)
do {
let encodedURLRequest = try encoding.encode(urlRequest, with: parameters)
return request(resource: encodedURLRequest)
} catch {
let request = self.request(resource: urlRequest)
request.delegate.error = error
return request
}
}
Basically, it uses the request without the parameters. I don't know how far it can be used in your own implementation (or How to migrate Alamofire router class to Swift 3? 's OP).
I'd suggest filing an issue with Alamofire if this is not possible. The new ParameterEncoding is literally two days old (PR 1465) and still in the 4.0.0 beta cycle.
In any case, using URLEncoding.encode() seldom fails if you set your own URLRequest because the only error thrown is when there's no URL provided with the request.
EDIT: Here you go, 4.0.0 released, and the issue's been fixed! (PR 1505). There have been other changes to URLRequestConvertible but all's in the Migration Guide and README.
I'm looking for a way to customize StrongLoop LoopBack HTTP response code and headers.
I would like to conform to some company business rules regarding REST API.
Typical case is, for a model described in JSON, to have HTTP to respond to POST request with a code 201 + header Content-Location (instead of loopback's default response code 200 without Content-Location header).
Is it possible to do that using LoopBack ?
Unfortunately the way to do this is a little difficult because LoopBack does not easily have hooks to modify all responses coming out of the API. Instead, you will need to add some code to each model in a boot script which hooks in using the afterRemote method:
Inside /server/boot/ add a file (the name is not important):
module.exports = function(app) {
function modifyResponse(ctx, model, next) {
var status = ctx.res.statusCode;
if (status && status === 200) {
status = 201;
}
ctx.res.set('Content-Location', 'the internet');
ctx.res.status(status).end();
}
app.models.ModelOne.afterRemote('**', modifyResponse);
app.models.ModelTwo.afterRemote('**', modifyResponse);
};
Example code snippet
this._deferred = dojo.io.iframe.send({
url: "/Some/Servie",
method: "post",
handleAs: 'html',
content: {},
load: function(response, ioArgs){
//DO successfull callback
},
error: function(response, ioArgs){
// DO Failer callback
}
});
Steps
click submit button send a request and successfully got a response
click submit button again...request never send...
Appreciate any help
I can't talk for 1.8, but I am using dojo 1.6 and had a very similar issue that I resolved with the following method:
dojo.io.iframe._currentDfd = null; //insert this line
dojo.io.iframe.send
({...
*verified in Chrome Version 25.0.1364.152 m
Source: http://mail.dojotoolkit.org/pipermail/dojo-interest/2012-May/066109.html
dojo.io.frame.send will only send one request at a time, so if it thinks that the first request is still processing (whether it actually is or not), it won't work on the second call. The trick is to call cancel() on the returned deferred result if one exists, like so:
if (this._deferred) {
this._deferred.cancel();
}
this._deferred = dojo.io.iframe.send({
....
that will cancel the first request and allow the second request to send properly.
For dojo 1.8, dojo.io.iframe is deprecated. dojo.request.iframe is used instead.
And the solution from #Sorry-Im-a-N00b still works:
iframe._currentDfd = null;
iframe.get(url, {
data: sendData,
});
It seems there is a problem with loading a specific instance (load() function) using the rest proxy in a model/store object. example:
Code:
Ext.regModel('User', {
fields: ['id', 'name', 'email'],
proxy: {
type: 'rest',
url : '/users'
}
});
//get a reference to the User model class
var User = Ext.ModelMgr.getModel('User');
//Uses the configured RestProxy to make a GET request to /users/123
User.load(123, {
success: function(user) {
console.log(user.getId()); //logs 123
}
});
This code is copied from Sencha touch's API. the generated URL is http://localhost/users?_dc=... instead of the desired (and documented) url http://localhost/users/123.
it also happens when using the store.load with a parameter.
Am I doing something wrong here?
Thanks
T
It seams the id parameter has been documented but not implemented. This has been discussed in the sencha forum [link]. A few non complete fixes are written in post #8 and post #13.