Multipart POST with Alamofire - swift

I want to make a request to my Rails server using Alamofire in Swift.
I have a simple object on that I would like to serialize as well as a few images that I would like to attach as multipart-encoded data.
On my rails side it is as simple as a request :
post :create, object: parameters, files: ['file1', 'file2'], format: :json
What's the most elegant way to do this with Alamofire?

I haven't dug to far into Alamo fire yet, but reading the documentation leads me to believe this is not supported in Alamo Fire at this time. Specifically the end of the document under the header "When should I use AFNetworking" states:
Use AFNetworking for any of the following:
UIKit extensions, such as asynchronously loading images to UIImageView
TLS verification, using AFSecurityManager
Situations requiring NSOperation or NSURLConnection, using AFURLConnectionOperation
Network reachability monitoring, using AFNetworkReachabilityManager
Multipart HTTP request construction, using AFHTTPRequestSerializer

I am not sure what you are asking
In Swift 3
But for Implementing MultiPartFormdata
Following Code Can be useful
Alamofire.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(UIImageJPEGRepresentation(self.Imgprofile.image!, 1)!, withName: "Prescription", fileName: "Profile_Image.jpeg", mimeType: "image/jpeg")
}, to:"Your URL Here")
{ (result) in
switch result {
case .success(let upload, _, _):
print(result)
upload.uploadProgress(closure: { (progress) in
print(progress)
})
upload.responseJSON { response in
//print response.result
print(response);
}
case .failure(let encodingError):
print(encodingError);
}
}
}
This Is The Latest Working Syntax

Related

Swift and Python HTTP Request "GET"

I am making an app that can upload an image to a python backend server with my friends, and I need a little bit help on the http request, was trying to use Alamofire but somehow it needs backend to revise, but the backend cannot be revised because it is already in used with another Android App.
So here is my question, do I need to set the multipart/form-data, and also would you please read my code and give me some suggestions? I will show both of my sides code,
my front end:
func myImageUploadRequest()
{
// convert image to data object
guard let imageData = UIImageJPEGRepresentation(myImageView.image!, 1) else {
print("Could not get JPEG representation of UIImage")
return
}
// send multipart request
Alamofire.upload( multipartFormData: { multipartFormData in
multipartFormData.append(imageData, withName: "imagefile", fileName: "image.jpg", mimeType: "image/jpeg")},
to: "http://123.123.123.123/image",
headers: ["Authorization": "Basic xxx"],
encodingCompletion: { encodingResult in
// check the response
switch encodingResult {
case .success(let upload, _, _):
upload.uploadProgress { progress in
// Show progress
}
upload.responseJSON { response in
// Handle response
}
case .failure(let encodingError):
print(encodingError)
// Handle Error
}
})
}
I am still confused about this part, so I now have an image select from gallery, and I use an UIImageJPEGRepresentation to represent the image in a UIImageView area, how can I use that part to send to the server?
The back end is very simple, it is :
#app.route("/image", methods=["GET", "POST"])
def image():
if(request.method == 'GET'):
return '{ Success }'
file = request.files['file']
img = Image.open(request.files['file'])
img.save(os.path.join(app.config['UPLOAD_FOLDER'], file.filename))
return classify_image.pic_tensorflow('/home/images/file.jpg')
Can anyone give any suggestions?
I have changed the info list for the http.
Here are the error I got from the console
2018-03-13 01:42:54.424642-0500 zechengpart[53957:9552037] TIC Read Status [2:0x60000017ec00]: 1:54
2018-03-13 01:42:55.803615-0500 zechengpart[53957:9552112] [] nw_socket_get_input_frames recvmsg(fd 8, 3734 bytes): [54] Connection reset by peer

Uploading image to third party service using alamofire and auth token

I have been trying to upload my image to a third party website using their api and alamofire to get some information back regarding the image that has been uploaded. I have to pass the auth token in with the request to get access to their resources, here is the instruction they have provided,
"Image should be specified by its url or uploaded with multipart form by parameter 'data'. You should use, respectively, GET and POST methods."
I have been trying to implement the upload method in 5 different ways but none of them seem to work I get a responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(Error Domain=NSCocoaErrorDomain Code=3840 \"Invalid value around character 2.\" UserInfo={NSDebugDescription=Invalid value around character 2.}))" error back here is one of the functions that takes care of the upload:
let headers: HTTPHeaders = [ "Authorization": "Bearer \(authToken)" ]
let URL = try! URLRequest(url: "url", method: .post, headers: headers)
Alamofire.upload(multipartFormData: { multipartFormData in
multipartFormData.append(imageData, withName: "signImg", fileName: "picture.png", mimeType: "image/png")
}, with: URL, encodingCompletion: {
encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
debugPrint("SUCCESS RESPONSE: \(response)")
}
case .failure(let encodingError):
// hide progressbas here
print("ERROR RESPONSE: \(encodingError)")
}
})
I also don't understand the meaning of the parameters used to append the multipartformdata such as withName, filetype, mimeType.
I would really appreciate if you could attach an explanation with the solution.

Alamofire multiple requests iteration

I have four different requests in my application, three of them requires one call only and the last requires from 1 - 10.
All works fine until the last request when I´m iterating through my data and making the calls. This is my code in Class1:
var data = ...
var points = ...
// I create a new group
let getPointGroup = dispatch_group_create()
// I iterate through my data
for d in data{
// I enter the group
dispatch_group_enter(getPointGroup)
dataService.getPoints(d.point), success: { points -> Void in
points.append(points)
// I leave the group so that I go to the next iteration
dispatch_group_leave(getPointGroup)
}
}
Alamofire request looks like this in Class2:
let headers = [
"Authorization": "Bearer \(token)",
"Content-Type": "application/x-www-form-urlencoded"
]
Alamofire.request(.GET, url, headers:headers)
.responseJSON { response in
switch response.result {
case .Success:
let json = JSON(data: response.data!)
print(json)
success(json)
case .Failure(let error):
print(error)
}
}
But I never hit the GET request, if I remove the iteration completely and just call the Alamofire request once it works perfectly.
Any ideas of how to solve the Alamofire iteration request?
Edit
Not really a duplicate, I have the snippets below in the different classes and the example does not really solve my issue
If this is not running, you could be deadlocking if you use dispatch_group_wait on the main thread, thereby blocking that thread, and preventing Alamofire from running any of its completion handlers (which also require the main thread). This is solved (assuming you are, indeed, using dispatch_group_wait), by replacing that with dispatch_group_notify.
Thus:
let group = dispatch_group_create()
for d in data {
// I enter the group
dispatch_group_enter(group)
dataService.getPoints(d.point)) { additionalPoints, error in
defer { dispatch_group_leave(group) }
guard let let additionalPoints = additionalPoints else {
print(error)
return
}
points.append(additionalPoints)
}
}
dispatch_group_notify(group, dispatch_get_main_queue()) {
// go to the next iteration here
}
Where:
func getPoints(point: WhateverThisIs, completionHandler: (JSON?, NSError?) -> ()) {
let headers = [
"Authorization": "Bearer \(token)"
]
Alamofire.request(.GET, url, headers: headers)
.responseJSON { response in
switch response.result {
case .Success:
let json = JSON(data: response.data!)
completionHandler(json, nil)
case .Failure(let error):
completionHandler(nil, error)
}
}
}
Now, I don't know what your various parameter types were, so I was left to guess, so don't get lost in that. But the key is that (a) you should make sure that all paths within your Alamofire method will call the completion handler; and (b) the caller should use dispatch_group_notify rather than dispatch_group_wait, avoiding the blocking of any threads.
Note, in order to make the completion handler callable even if the network request failed, I had to make the parameter to that closure optional. And while I was there, I added an optional error parameter, too.
A few unrelated changes included in the above sample:
I'd suggest using a different variable name for the parameter of your closure. The points.append(points) in your original code snippet suggests some confusion between your points array and the points that is passed back in the closure.
You don't have to set the Content-Type header, as Alamofire does that for you.
I didn't change it above, but it is inefficient to use responseJSON (which uses NSJSONSerialization to parse the JSON) and then use SwiftyJSON to parse the raw data with NSJSONSerialization again. Personally, I don't bother with SwiftyJSON, but if you want to use it, I'd suggest use Alamofire's response method rather responseJSON. There's no point in parsing the JSON twice.

RESTful mechanism to upload video (and properties) to vimeo

The procedure to upload a video to Vimeo starts out very similarly as the one defined for Youtube, but only up to a point. Below I describe the steps that worked, and outline the last video-upload step which does not:
The Vimeo-upload dance begins when we pass the following parameters to trigger user authentication:
let authPath:String = "\(url_vauth)?response_type=\(response_type)&client_id=\(client_id)&redirect_uri=\(redirect_uri)&state=\(state)&scope=upload"
if let authURL:NSURL = NSURL(string: authPath) {
let request = NSURLRequest(URL: authURL)
webView.loadRequest(request) // opens a webpage in a webUIView
// once credentials are entered, google redirects back with the above uri + a temporary code
// we will exchange later for a token
// within AppDelegate, we have defined a way to handle this uri, which is to call
// processOAuthStep1Response(url)
Then, we process the returned response to extract an authorization code:
let components = NSURLComponents(URL: url, resolvingAgainstBaseURL: false)
var auth_code:String!
// the block below extracts the text that follows "code" in the return url
if let queryItems = components?.queryItems {
for queryItem in queryItems { // step through each part of url
if queryItem.name.lowercaseString == "code" {
auth_code = queryItem.value
break
} // end of if queryItem.name.lowercaseString
} // end of for
} // if let queryItems
With this authorization code, we then generate a token:
let getTokenPath:String = url_token
let grant_type = "authorization_code"
let header_plain = "\(client_id):\(client_secret)"
let string_plain = header_plain.dataUsingEncoding(NSUTF8StringEncoding)
let string_base64 = (string_plain?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0)))! as String
let headers = ["Authorization": "basic \(string_base64)"] // note that string_base64 really needs to be in base64!
//print ("...header is: \(string_base64)")
let tokenParams = ["grant_type": grant_type, "code": receivedCode, "redirect_uri": redirect_uri, "scope": "public"]
let request = Alamofire.request(.POST, getTokenPath, parameters: tokenParams, encoding: .URL, headers: headers)
We use this token to generate a ticket:
request(.POST, url_getticket, parameters: ticketParams , encoding: .URL, headers: headers).responseJSON { response in
//print(response)
switch response.result {
case .Success(let data):
let json = JSON(data)
print (json)
let myticket = json["ticket_id"].stringValue
//let usage = json[("upload_quota")].stringValue
let htmlform = json[("form")].stringValue
let uploadlink = json[("upload_link_secure")].stringValue
print("......ticket is \(myticket)")
print("......form is \(htmlform)")
print("......upload link is \(uploadlink)")
case .Failure(let error):
print("Request failed with error: \(error)")
} // end of switch
Finally (and this is where things stop to a screeching halt) we are supposed to use this ticket to make a POST request to Vimeo. The problem is that this ticket is embedded in an html form that actually makes the upload request to Vimeo...Not very useful for the iOS platform where I'm trying to implement this. Ideally, I'd like implementing with Alamofire via an upload call like so:
let headers = ["Authorization": "Bearer \(token)"]
upload(
.POST,
"https://1511923767.cloud.vimeo.com/upload?ticket_id=#######&video_file_id=####&signature=####&v6=1&redirect_url=https%3A%2F%2Fvimeo.com%2Fupload%2Fapi%3Fvideo_file_id%3D498216063%26app_id%3D70020%26ticket_id%####%26signature%######",
headers: headers,
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(data: videodata, name: "video", fileName: "bagsy.m4v", mimeType: "application/octet-stream")
},
encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
dispatch_async(dispatch_get_main_queue()) {
let percent = (Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))
//progress(percent: percent)
print ("................\(percent)")
}
}
upload.validate()
upload.responseJSON { response in
print(response)
callback(true)
}
case .Failure(_):
callback(false)
}
})
Needless to say, the chunk of code above does not work. Any guidance would be most appreciated.
Consider using the official Vimeo iOS Upload SDK. We made it public about 2 weeks ago. It's a Swift library that handles upload of video files to Vimeo servers. It does so using a background-configured NSURLSession (so uploads continue regardless of whether your app is in the foreground or background). Let us know if you have any questions. Note: I'm one of the authors of the library and I work at Vimeo.
The VimeoUpload README is pretty robust and should communicate all that you need to know. Lettuce know if you have additional questions though, or feel free to make a pull request.
The ticket is never manually used in an upload. You should always use the url, or html provided by the API.
If you see HTML, it's because you are not providing the "type" parameter. We default to a simple POST upload system as described here: https://developer.vimeo.com/api/upload/videos#simple-http-post-uploading
If you provide "type=streaming", Vimeo returns a "complete_url", which you must call after performing the streaming upload as described here: https://developer.vimeo.com/api/upload/videos#resumable-http-put-uploads

Alamofire HTTP sent twice SWIFT

every one,
I'm having an issue with Alamofire 3.0, when I post data, it seems the data is being sent twice.
I looked up on the web, found that a bug about special caratères was fixed, but I still get the error.
Anyone has an idea. I'm using a parameter in the header called X-Authorization.
Here is an extract of the code i'm using:
static func postData (url: String,token: String,params :Dictionary<String,AnyObject>){
print("POSTINGGGGGG")
Alamofire.request(.POST, url, parameters: params,headers: ["X-Authorization": token])
.responseJSON { response in
switch response.result {
case .Success(let data): break
//let resultJSON = JSON(data).dictionaryValue
// print(data)
case .Failure(let error):
print(error)
}
}
}
Thank you in advance,
Morgan