how to use form data in Alamofire - swift

In the postman in the body section in the form-data part when I pass a mobile number as a key and mobile number as Int value I get a response. But when I did it in the code I will not get the response as expected.
my code is
func fetchRegisterData(){
let url = registerApi
var mobileNumber = mobilenumberTextfield.text
let parameters = ["mobile" : mobileNumber] as [String : Any]
AF.request(url,method: .post, parameters: parameters, encoding:JSONEncoding.default).responseJSON
{ response in switch response.result {
case .success(let JSON):
print("response is :\(response)")
case .failure(_):
print("fail")
}
}
}

If you're trying to pass parameters as multipart/form-data you have to use the upload method in Alamofire:
func fetchRegisterData() {
let parameters = ["mobile": mobilenumberTextfield.text!]
AF.upload(multipartFormData: { (multiFormData) in
for (key, value) in parameters {
multiFormData.append(Data(value.utf8), withName: key)
}
}, to: registerApi).responseJSON { response in
switch response.result {
case .success(let JSON):
print("response is :\(response)")
case .failure(_):
print("fail")
}
}
}

For normal Alamofire request -
While passing values as a parameter in Alamofire Request. You need to know about the data type of the request type values which is valid for API.
At API end, these values are getting parsed based on some data types. There must be some validations on the data type at the API side.
for mobileNumber, it can be either Int or String
1 - let parameters = ["mobile" : mobileNumber] as [String : Int]
2 - let parameters = ["mobile" : mobileNumber] as [String : String]
For multipart form data request use have to use something like below. However, if you are not uploading anything you should not use it. Ask API team to make changes in the API and normal parameters request
Alamofire.upload(multipartFormData: { (multipartFormData) in
//Try this
multipartFormData.append(mobileNumber, withName: "mobile")
//or this
multipartFormData.append("\(String(describing: mobileNumber))".data(using: .utf8)!, withName: "mobile")
}, usingThreshold: 10 * 1024 * 1024, to: apiUrl, method: .post, headers: [:], encodingCompletion: { (encodingResult) in
switch encodingResult {
case .success(let upload, _, _):
case .failure( _):
}
})

Related

Alamofire get method with parameters in the url with header swift

I have a get method with 3 parameters on the base url itself.I have tried the following code, but it is going to failure condition saying either not a valid url or not a valid JSON.
What is the correct way to approach this?
The code i have used is as below:
let header: HTTPHeaders = ["Content-Type":"application/json","x-token":self.token!]
let todosEndpoint: String = "https://reachwebdemo.com/2020/10/listcribdev/api/chatnotification?" + "channel_sid=\(self.channelsid!)&author=\(self.userid!)&message=\(inputMessage)"
if let encoded = todosEndpoint.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed),let url = URL(string: encoded)
{
print("notify url is",url)
AF.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: header).responseString { response in
switch response.result {
case .success(let json):
print("Validation Successful for push notification",json)
case let .failure(error):
print("error for push notificaton",error.errorDescription)
}
}
}
You user parameters like url and it's wrong way to make request like this.
You need add parameters on request method like parameters. And yes, you can use parameters on 'GET' requests.
let header: HTTPHeaders = ["Content-Type":"application/json","x-token":self.token!]
let todosEndpoint: String = "https://reachwebdemo.com/2020/10/listcribdev/api/chatnotification"
let params:[String: Any] = ["channel_sid":self.channelsid!, "author":self.userid!, "message": inputMessage]
if let encoded = todosEndpoint.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed),
let url = URL(string: encoded) {
print("notify url is",url)
AF.request(url, method: .get, parameters: params, encoding: URLEncoding.default, headers: header).responseString { response in
switch response.result {
case .success(let json):
print("Validation Successful for push notification",json)
case let .failure(error):
print("error for push notificaton",error.errorDescription)
}
}
}

Issue while hitting Post Method api in swift

I'm trying to call an API in which I'm trying to send some parameters and array of images, but when I hit the API I get an error, Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber dataUsingEncoding:]: unrecognized selector sent to instance 0xfb47bab3e1e91166'. I have checked through breakpoint it crashes on parameters, I'm confused why it is giving this error, my code for the API is this,
func addAPI()
{
let headers: HTTPHeaders = [
/* "Authorization": "your_access_token", in case you need authorization header */
"Content-type": "multipart/form-data"
]
let parameters :[String: Any] = ["name":productNameTxt.text!,
"price":priceTxt.text!,
"size": sizeTxt.text!,
"weight":weightTxt.text!,
"quality":qualityTxt.text!,
"brand":brandTxt.text!,
"shippingCost":shippingCostTxt.text!,
"details":detailTxt.text!,
"material_id":materialId,
"material_type_id": subMaterialId,
"maxQuantity":4]
Alamofire.upload(multipartFormData: { multipartFormData in
for (key, value) in parameters {
if let data = ((value) as AnyObject).data(using: String.Encoding.utf8.rawValue) {
multipartFormData.append(data, withName: key)
}
}
for (index, image) in self.imageArray.enumerated() {
multipartFormData.append(image.pngData()!, withName: "file", fileName: "image\(index).png", mimeType: "image/png")
}
// for i in 0..
},
to: addProductUrl,method:HTTPMethod.post,
headers:headers, encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload
.validate()
.responseJSON { response in
switch response.result {
case .success(let value):
// compBlock(value as AnyObject,true)
print("responseObject: \(value)")
case .failure(let responseError):
print("responseError: \(responseError)")
}
}
case .failure(let encodingError):
print("encodingError: \(encodingError)")
let errorDesc = (encodingError as NSError).localizedDescription
//failure(errorDesc as NSString,false)
}
})
}
What is this error for and how I can remove it?
From here
if let data = ((value) as AnyObject).data(using: String.Encoding.utf8.rawValue) {
then any passed value have to be converted to Data and since you specify an integer ( NSNumber when wrapped inside json) hence the crash so change 4 to "4" and
"material_id":"\(materialId)",
It would be better if you follow like this:
//[String:String] instead of [String : Any]
let parameters :[String: String] = ["name":productNameTxt.text!,
"price":priceTxt.text!,
"size": sizeTxt.text!,
"weight":weightTxt.text!,
"quality":qualityTxt.text!,
"brand":brandTxt.text!,
"shippingCost":shippingCostTxt.text!,
"details":detailTxt.text!,
"material_id":"\(materialId)",
"material_type_id": subMaterialId,
"maxQuantity":4]
multipartFormData.append((value.data(using: .utf8))!, withName: key)

Upload audio binary file using Alamofire

I'm trying to upload an audio binary file to a server using Alamofire along with parameters and headers. Whenever I add the parameters; I get an error saying ambigious reference call to member error. I have checked the API online and haven't found a way to pass in parameters. Is there a way to do so?
let headersFileUpload: HTTPHeaders = ["Authorization": "JWT "+token!]
let parametersFileUpload: Parameters = ["ctype":"yes"]
Alamofire.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(self.getDocumentsDirectory().appendingPathComponent("recording.m4a"), withName: "iosTest.mp3")
},
to: "http://localhost:8000/api/upload",
method:.post,
headers:headersFileUpload,
parameters:parametersFileUpload
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
debugPrint(response)
}
case .failure(let encodingError):
print(encodingError)
}
}
)

Thread 1 : signal SIGABRT alamofire

I'm very new to Swift 3, and i have to do a GET request on my API. I'm using Alamofire, which uses Asynchronous functions.
I do exactly the same on my Android App, and the GET returns JSON data
This is my code in swift :
func getValueJSON() -> JSON {
var res = JSON({})
let myGroup = DispatchGroup()
myGroup.enter()
Alamofire.request(url_).responseJSON { response in
res = response.result.value as! JSON
print("first result", res)
myGroup.leave()
}
myGroup.notify(queue: .main) {
print("Finished all requests.", res)
}
print("second result", res)
return res
}
But i have a problem with the line "res = response.result.value" wich gives me the error : Thread 1 : signal SIGABRT
I really don't understand where the problem comes from, it was pretty hard to do a "synchronous" function, maybe i'm doing it wrong.
My objective is to store the result of the request in a variable that i return. Anyone can help ?
I'd recommend you to use Alamofire together with SwiftyJSON because that way you'll be able to parse JSON easier a lot.
Here's a classical example:
Alamofire.request("http://example.net", method: .get).responseJSON { response in
switch response.result {
case .success(let value):
let json = JSON(value)
print("JSON: \(json)")
case .failure(let error):
print(error)
}
}
If you need to pass parameters, or headers, just add it in the request method.
let headers: HTTPHeaders = [
"Content-Type:": "application/json"
]
let parameters: [String: Any] = [
"key": "value"
]
So your request will be something like this (this is POST request):
Alamofire.request("http://example.net", method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: headers).responseJSON { response in
switch response.result {
case .success(let value):
print(value)
case .failure(let error):
print(error)
}
}
I haven't tested it, but it should work. Also, you need to set allow arbitary load to yes (App Transport Security Settings in info.plist) if you want to allow requests over HTTP protocol.
This is NOT recommended, but it's fine for development.

How to cancel Alamofire.upload

I am uploading images on server via Alamofire.upload as multipart data. Unlike Alamofire.request it's not returning Request object, which I usually use to cancel requests.
But it's very reasonable to be able to cancel such a consuming requests like uploading. What are the options for this in Alamofire?
Using the Uploading MultiPartFormData example from the Alamofire README:
Alamofire.upload(
.POST,
"https://httpbin.org/post",
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(fileURL: unicornImageURL, name: "unicorn")
multipartFormData.appendBodyPart(fileURL: rainbowImageURL, name: "rainbow")
},
encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.responseJSON { response in
debugPrint(response)
}
case .Failure(let encodingError):
print(encodingError)
}
}
)
Here, upload.responseJSON returns a Request, which should allow you to assign it to something for cancellation later. For example:
let request = upload.responseJSON { ...
...
request.cancel()
I'm afraid you can't, according to the Alamofire source code the upload function returns an Request type in all of its overloads except in these that support MultipartFormData see the following code:
// MARK: MultipartFormData
/**
Creates an upload request using the shared manager instance for the specified method and URL string.
- parameter method: The HTTP method.
- parameter URLString: The URL string.
- parameter headers: The HTTP headers. `nil` by default.
- parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`.
- parameter encodingMemoryThreshold: The encoding memory threshold in bytes. `MultipartFormDataEncodingMemoryThreshold`
by default.
- parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete.
*/
public func upload(
method: Method,
URLString: URLStringConvertible,
headers: [String: String]? = nil,
multipartFormData: MultipartFormData -> Void,
encodingMemoryThreshold: UInt64 = Manager.MultipartFormDataEncodingMemoryThreshold,
encodingCompletion: (Manager.MultipartFormDataEncodingResult -> Void)?)
{
return Manager.sharedInstance.upload(
method,
URLString,
headers: headers,
multipartFormData: multipartFormData,
encodingMemoryThreshold: encodingMemoryThreshold,
encodingCompletion: encodingCompletion
)
}
/**
Creates an upload request using the shared manager instance for the specified method and URL string.
- parameter URLRequest: The URL request.
- parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`.
- parameter encodingMemoryThreshold: The encoding memory threshold in bytes. `MultipartFormDataEncodingMemoryThreshold`
by default.
- parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete.
*/
public func upload(
URLRequest: URLRequestConvertible,
multipartFormData: MultipartFormData -> Void,
encodingMemoryThreshold: UInt64 = Manager.MultipartFormDataEncodingMemoryThreshold,
encodingCompletion: (Manager.MultipartFormDataEncodingResult -> Void)?)
{
return Manager.sharedInstance.upload(
URLRequest,
multipartFormData: multipartFormData,
encodingMemoryThreshold: encodingMemoryThreshold,
encodingCompletion: encodingCompletion
)
}
It's recommended when you are writing client-side code, use multipart/form-data when your form includes any <input type="file"> elements.
So if you want to just upload an image to the server you can use the another upload function overloads that returns an Request object and you can cancel it like in this ways proposed in the Alamofire documentation:
let fileURL = NSBundle.mainBundle().URLForResource("Default", withExtension: "png")
ler request =Alamofire.upload(.POST, "https://httpbin.org/post", file: fileURL)
// request.cancel()
I hope this help you.
It's possible to prepare a closure, and transfer a request out of "encodingCompletion"
class NetworkManager {
private var closure: ((Request)->())?
func startUpload() {
Alamofire.upload(
.POST,
"https://httpbin.org/post",
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(fileURL: unicornImageURL, name: "unicorn")
multipartFormData.appendBodyPart(fileURL: rainbowImageURL, name: "rainbow")
},
encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
self.closure?(upload)
upload.responseJSON { response in
debugPrint(response)
uploadRequest = nil
}
case .Failure(let encodingError):
print(encodingError)
}
}
)
}
}
In my case I created "sessionManager" instance in my API class and assigned Alamofire's session manager with configuration to it.
var sessionManager: SessionManager!
// Setup request manager
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForResource = TimeInterval(15.0)
configuration.timeoutIntervalForRequest = TimeInterval(15.0)
sessionManager = Alamofire.SessionManager(configuration: configuration)
sessionManager.upload(multipartFormData: { multipartFormData in
// AppendMultipart parts
multipartFormData.append(metadataBodyPart, withName: PartName.Metadata, mimeType: MimeType.MultiPart)
multipartFormData.append(imageDataBodyPart, withName: PartName.Photo, mimeType: MimeType.ImageJPG)
} // ... rest of the code
Then I could create a method to cancel any current request type. Note that here "(_, uploadTasks, _)" you can also have "dataTasks" & "downloadTasks" which you can also cancel if you want "(dataTasks, uploadTasks, downloadTasks)"
func cancelUploadRequest() {
sessionManager.session.getTasksWithCompletionHandler { (_, uploadTasks, _) in
uploadTasks.forEach { $0.cancel() }
}
}
You can also have smth like this:
func cancel(request: CancelRequestType) {
sessionManager.session.getTasksWithCompletionHandler { (dataTasks, uploadTasks, downloadTasks) in
switch request {
case .DataTask:
dataTasks.forEach { $0.cancel() }
print("- - - Data task was canceled!")
case .UploadTask:
uploadTasks.forEach { $0.cancel() }
print("- - - Upload task was canceled!")
case .DownloadTask:
downloadTasks.forEach { $0.cancel() }
print("- - - Download task was canceled!")
case .ZeroTask:
print("- - - Zero tasks was found!")
}
}
}
Where "CancelRequestType" is enum. So you can call the method like API.cancel(request: .UploadTask)
enum CancelRequestType: String {
case DownloadTask = "DownloadTask"
case DataTask = "DataTask"
case UploadTask = "UploadTask"
case ZeroTask = "Zero"
}