Alamofire Completion Handler returning response + data - ios

I have a function that includes a responseObject in it's completion handler. At the moment this returns the json body when I call it, along with any errors.
Some parts of the API I am using however, don't return any data in the response body, they just return a response (200, 404, etc...)
I was thinking about appending the response inside the empty json object that is getting returned, then realised that would be silly and it would probably be better if I returned the NSHTTPURLResponse as well, but everything I have found just explains how to return the responseObject along with the error...
This is the function that returns the completion handler:
func makePostRequest(url : String, params : AnyObject, completionHandler: (responseObject: NSHTTPURLResponse, JSON?, error: NSError?) -> ()) -> Request? {
println("params = \(params)")
return Alamofire.request(.POST, url, parameters: params as? [String : AnyObject], encoding: .JSON)
.responseJSON { (request, response, data, error) in completionHandler(
//This is wrong
response: response as? NSHTTPURLResponse,
responseObject:
{
println("Request is \(request)")
println("Response is \(response)")
println("Data is \(data)")
println("Error is \(error)")
//Append the response to this JSON object?
//
var json:JSON = [:]
if let anError = error
{
println(error)
}
else if let data: AnyObject = data
{
json = JSON(data)
}
//probably better to return the two...
//
return (response, json)
}(),
error: error
)
}
}
And this is how its used:
networking.makePostRequest(documentUrl, params: docParams) { response, json, error in
println("response is: \(response)")
println("document json: \(json)")
println("document error: \(error)")
}
I've added in the 'response' bits to all the bits of code, i'm sure this is possible? just not sure how to achieve it..

For anyone stuck trying to figure out how to return stuff this way, I solved it like this:
func makePostRequest(url : String, params : AnyObject, completionHandler: (httpResponse: NSHTTPURLResponse, responseObject:JSON?, error: NSError?) -> ()) -> Request? {
println("params = \(params)")
return Alamofire.request(.POST, url, parameters: params as? [String : AnyObject], encoding: .JSON)
.responseJSON { (request, response, data, error) in completionHandler(
//This is wrong
httpResponse: response!,
responseObject:
{
println("Request is \(request)")
println("Response is \(response)")
println("Data is \(data)")
println("Error is \(error)")
//Append the response to this JSON object?
//
var json:JSON = [:]
if let anError = error
{
println(error)
}
else if let data: AnyObject = data
{
json = JSON(data)
}
return json
}(),
error: error
)
}
}
and then calling it like this:
networking.makePostRequest(workDocumentUrl, params: params) { response, json, error in
if response.statusCode == 200{
//do something
}
println("json: \(json)")
println("error: \(error)")
}

Related

Swift 3 using AFNetworking

I am using AFNetworking with Swift 3.0 and I am stuck on one code.
func getJSON()
{
let manager = AFHTTPSessionManager()
manager.get(
url,
parameters: nil,
success:
{
(operation: URLSessionTask!, responseObject: Any?) in
print("JSON: " + responseObject!.description)
self.matchesArray = responseObject!.object(forKey: "matches")! as? NSMutableArray
self.tollBothPlazaTableView.reloadData()
},
failure:
{
(operation: URLSessionTask!, error: NSError) in
print("Error: " + error.localizedDescription)
}
)
}
It shows error on failure block.
Cannot convert value of type '(URLSessionTask!, NSError) -> ()' to expected argument type '((URLSessionDataTask?, Error) -> Void)?'`
Can someone explain what is wrong in my code. Also the correct way to use closures? (I am new to swift).
Error is clearly saying that use Error instead of NSError, in Swift 3 you need to use Error instead of NSError. So change your code like below.
func getJSON() {
let manager = AFHTTPSessionManager()
manager.get(
url,
parameters: nil,
success:
{
(operation, responseObject) in
if let dic = responseObject as? [String: Any], let matches = dic["matches"] as? [[String: Any]] {
print(matches)
}
DispatchQueue.main.async {
self.tollBothPlazaTableView.reloadData()
}
},
failure:
{
(operation, error) in
print("Error: " + error.localizedDescription)
})
}
Note: Always perform UI changes on main thread when you are on background thread, so batter to reload your tableView on main thread like I have done, Also use Swift native Array and Dictionary instead of NSArray and NSDictionary.
**Its Better to use Alamofire(same developer) in swift 3 **
func jsonRequest()
{
let url = "url"
//if you want to add paramter
parametr = ["username" : "user" , "password"]
Alamofire.request(url, method: .post, parameters: nil, encoding: JSONEncoding.default)
.responseJSON { response in
// print(response)
//to get status code
if let status = response.response?.statusCode {
switch(status){
case 201:
print("example success")
default:
print("error with response status: \(status)")
}
}
//to get JSON return value
if let array = response.result.value as? //NSDictionary [[String : Any]]
{
}
}
}

how i can make a HTTP request with Swift 3?

Im learning about Swift and i trying to make an HTTP request. My code is working but i dont know how to return the result of the request:
func makeRequest(request: URLRequest)->String{
let task = URLSession.shared.dataTask(with: request){data, response, error in
guard let data = data, error == nil else{
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
print (data)
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print(json)
} catch {
print("error serializing JSON: \(error)")
}
//print("responseString = \(responseString)")
}
task.resume()
return "Something"//i need to return the json as String
}
Someone can help me please? i was trying using CompletionHanlder but all the example that i found is based on swift 2, and this causes error on my code
The completion handler's type needs to be something like this:
#escaping ({argument types...})->{result type}
#escaping is needed as the completion handler is executed later when the communication is completed.
{argument types...} needs to be the types you want to pass to the handler, so in your case, a single type String. And you usually do not use the result from the handler, so you need to specify Void (aka ()).
Thus your completion handler's type needs to be:
#escaping (String)->Void
So, your method header becomes:
(You know you need a closing parenthesis for argument list.)
func makeRequest(request: URLRequest, completion: #escaping (String)->Void)
Whole your method would be something like this:
func makeRequest(request: URLRequest, completion: #escaping (String)->Void) {
let task = URLSession.shared.dataTask(with: request) {data, response, error in
guard let data = data, error == nil else{
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
print(data as NSData) //<-`as NSData` is useful for debugging
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print(json)
//Why don't you use decoded JSON object? (`json` may not be a `String`)
} catch {
print("error serializing JSON: \(error)")
}
//Not sure what you mean with "i need to return the json as String"
let responseString = String(data: data, encoding: .utf8) ?? ""
completion(responseString)
}
task.resume()
}
You can use it as:
makeRequest(request: request) {response in //<-`response` is inferred as `String`, with the code above.
print(response)
}
func makeRequest(request: URLRequest, completion: (result : String?)->() {
let task = URLSession.shared.dataTask(with: request){data, response, error in
guard let data = data, error == nil else{
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
print (data)
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print(json)
} catch {
print("error serializing JSON: \(error)")
}
completion("yourResultString")
//print("responseString = \(responseString)")
}
task.resume()
}
to call it
makeRequest(request: request) { (result : String?) in
if let result = result {
print("got result: \(result)")
}
You can't "return" the result of the request. By the time you have a result your makeRequest function has already returned to its caller. You should:
Change makeRequest to not return anything, because there's no
point
Replace the commented-out print statement with code that does
something with the responseString result.

Get JSON result with GET request and parameters with Alamofire

This is my url String with paramaters.
http://api.room2shop.com/api/product/GetProducts?categoryId=22&filter=2&pageNumber=1 through which I am getting my JSON data. I have AFWrapper.swift file in which I have defined function for GETrequest.
import UIKit
import Alamofire
import SwiftyJSON
class AFWrapper: NSObject {
class func requestGETURL(strURL: String, params : [String : AnyObject]?, success:(JSON) -> Void, failure:(NSError) -> Void) {
Alamofire.request(.GET, strURL, parameters: params, encoding: ParameterEncoding.JSON).responseJSON { (responseObject) -> Void in
print(responseObject)
if responseObject.result.isSuccess {
let resJson = JSON(responseObject.result.value!)
success(resJson)
}
if responseObject.result.isFailure {
let error : NSError = responseObject.result.error!
failure(error)
}
}
}
}
Now I am calling this function in my ViewController.swift file.
let strURL = "http://api.room2shop.com/api/product/GetProducts"
let param = ["categoryId": "22", "filter": "2", "pageNumber": "1"]
AFWrapper.requestGETURL(strURL, params: param, success: {
(JSONResponse) -> Void in
if let resData = JSONResponse["ProductList"].arrayObject {
for item in resData {
self.TableData.append(datastruct(add: item as! NSDictionary))
}
do
{
try self.read()
}
catch
{
}
self.do_table_refresh()
}
}) {
(error) -> Void in
print(error)
}
but it is not giving me any response and giving me this error.
FAILURE: Error Domain=NSURLErrorDomain Code=-1017 "cannot parse
response"
UserInfo={NSErrorFailingURLStringKey=http://api.room2shop.com/api/product/GetProducts,
_kCFStreamErrorCodeKey=-1, NSErrorFailingURLKey=http://api.room2shop.com/api/product/GetProducts,
NSLocalizedDescription=cannot parse response,
_kCFStreamErrorDomainKey=4, NSUnderlyingError=0x78ecf180 {Error Domain=kCFErrorDomainCFNetwork Code=-1017 "(null)"
UserInfo={_kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-1}}}
Error Domain=NSURLErrorDomain Code=-1017 "cannot parse response"
UserInfo={NSErrorFailingURLStringKey=http://api.room2shop.com/api/product/GetProducts,
_kCFStreamErrorCodeKey=-1, NSErrorFailingURLKey=http://api.room2shop.com/api/product/GetProducts,
NSLocalizedDescription=cannot parse response,
_kCFStreamErrorDomainKey=4, NSUnderlyingError=0x78ecf180 {Error Domain=kCFErrorDomainCFNetwork Code=-1017 "(null)"
UserInfo={_kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-1}}}
Can anyone tell me what am I doing wrong? I have seached this link but not getting what is wrong. URL Encode Alamofire GET params with SwiftyJSON
i think you should remove the parameter of "encoding: ParameterEncoding.JSON",like this:
Alamofire.request(.GET, strURL, parameters: params).responseJSON { (responseObject) -> Void in
print(responseObject)
if responseObject.result.isSuccess {
let resJson = JSON(responseObject.result.value!)
success(resJson)
}
if responseObject.result.isFailure {
let error : NSError = responseObject.result.error!
failure(error)
}
}
Use this code. It is retrieving response correctly parsed in JSON.
Using Alamofire v3.0+
Alamofire.request(.GET, "http://api.room2shop.com/api/product/GetProducts?categoryId=22&filter=2&pageNumber=1")
.responseJSON { response in
debugPrint(response)
switch response.result {
case .Success(let JSON):
print(JSON)
case .Failure(let error):
print(error)
}
}
EDIT:
For accepting Parameters with GET Type Service:
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
.responseData { response in
print(response.request)
print(response.response)
print(response.result)
}
In this case try to not manipulate your URL String and send all parameters in terms of Dictionary like this.
Your requestGETURL should look like that
func requestGETURL(strURL: String, params: [String:String]?, success: (AnyObject?) -> Void, failure: (NSError) -> Void) {
Alamofire.request(.GET, strURL, parameters: params).responseJSON {
(responseObject) -> Void in
print(responseObject)
if responseObject.result.isSuccess {
let resJson = JSON(responseObject.result.value!)
success(resJson)
}
if responseObject.result.isFailure {
let error: NSError = responseObject.result.error!
failure(error)
}
}
}
Your problem was in params it should be [String:String] dictionary. Also you don't have to declare encoding encoding:ParameterEncoding.JSON.
Hope it help you

Alomofire POST request in swift

I am using the following code in my swift 2.0 project. I cannot add Alamofire.request though I added "import Alamofire". I have to create object of Alamofire and then access through it.
This is how I create the object :
let manager = Alamofire.Manager.sharedInstance
manager.request(NSURLRequest(URL: NSURL(string: "http://httpbin.org/get")!))
let parameters = ["foo": "bar"]
manager.request(.POST, "url", parameters: parameters)
.responseJSON { request, response, json, error in
print("request: \(request)")
}
I am new to both Alamofire and swift. Can anybody tell how can I get response from the above code in a completion handler and why I cannot use Alamofire.request instead of manager.request.
Please see my Post method and Hope It helps
Post Method:
/**
** POST Method for calling API
* Services gateway
* Method get response from server
* #parameter -> requestObject: request josn object ,apiName: api endpoint
* #returm -> void
* #compilationHandler -> success: status of api, response: respose from server, error: error handling
**/
static func getDataWithObject( requestObject: NSDictionary, apiName : NSString,
completionHandler:
(success : Bool, response : NSDictionary, error : ErrorType?) -> Void) {
// Make Url
let url = NSURL(string: apiName as String)
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
//request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// Call the method to request and wait for the response
// #param ->
// #return ->
Alamofire.request(.POST, url!, parameters:requestObject as? [String : AnyObject], encoding: .JSON)
.responseJSON {responseRequest, responseResponse, responseResult in
// Switch for Success or Error
switch responseResult {
// If the API return succesfull response
case .Success(let data):
let data_ar = data as! NSDictionary
print(data_ar)
// Get the Status if 0 then error if 1 then succes
// From our server side
if let str = data_ar.valueForKey("OK") as? Bool {
// Check if the status is OK and no error from
// our server side
if ( str ) {
print("Response from Server %#", data_ar)
// Cast the response and pss to handler
// To notify
completionHandler(success: true, response:data_ar
, error:responseResult.error )
} else {
print("Error from Our Server %#", data_ar)
let str = data_ar.valueForKey("message") as! NSString
self.showAlertView(str, title: "Error From Server")
}
}
case .Failure(let data, let error):
print("Request failed with error: \(error)")
print(data)
print((error as! NSError).localizedDescription)
self.showAlertView((error as! NSError).localizedDescription, title: "Error From Server")
}
}
}
Request not always in JSON please check your request :
Following are examples to use Alamofire with the Swift 2 :
GET - JSON
Alamofire.request(.GET, "http://api.androidhive.info/contacts/", parameters: nil, encoding: .JSON, headers: nil).responseJSON { (req, res, json) -> Void in
print("\(res?.allHeaderFields)")
print("\(json.value!)")
}
POST - without JSON
Alamofire.request(.POST, "http://httpbin.org/get", parameters: ["foo": "bar"], encoding: .URL, headers: nil).response { (req, res, data, error) -> Void in
print(res)
print(data)
let dataString = NSString(data: data!, encoding:NSUTF8StringEncoding)
print(dataString)
}

Handle unknown content-type of response with Alamofire

I use Alamofire to do requests to a rest service. If the request is successful the server returns a JSON with content-type application/json. But if the request fails the server returns a simple String.
So, I don't know how to handle on it with Alamofire, because I don't know how the response look like. I need a solution to handle on the different response types.
This code I can use to handle on a successful request:
request(.POST, wholeUrl, parameters: parameters, encoding: .Custom(encodingClosure))
//.validate()
.responseJSON {
(request, response, data, error) -> Void in
//check if error is returned
if (error == nil) {
//this crashes if simple string is returned
JSONresponse = JSON(object: data!)
}
And this code I can use to handle on failed request:
request(.POST, wholeUrl, parameters: parameters, encoding: .Custom(encodingClosure))
//.validate()
.responseString {
(request, response, data, error) -> Void in
//check if error is returned
if (error == nil) {
responseText = data!
}
Don't specify the response type, and don't comment out the .validate().
Check for error, and then proceed accordingly
request(.POST, wholeUrl, parameters: parameters, encoding: .Custom(encodingClosure))
.validate()
.response {
(request, response, data, error) -> Void in
//check if error is returned
if (error == nil) {
//this is the success case, so you know its JSON
//response = JSON(object: data!)
}
else {
//this is the failure case, so its a String
}
}
I've solved my problem:
request(.POST, wholeUrl, parameters: parameters, encoding: .Custom(encodingClosure))
.validate()
.response {
(request, response, data, error) -> Void in
//check if error is returned
if (error == nil) {
var serializationError: NSError?
let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(data! as! NSData, options: NSJSONReadingOptions.AllowFragments, error: &serializationError)
JSONresponse = JSON(object: json!)
}
else {
//this is the failure case, so its a String
}
}
Swift 4
If you are expecting JSON on success and a String on error, you should call the .validate() hook and try parsing the response data as a string if the request fails.
import Alamofire
import SwiftyJSON
...
Alamofire.request("http://domain/endpoint", method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil)
.validate()
.responseJSON(completionHandler: { response in
if let error = response.error {
if let data = response.data, let errMsg = String(bytes: data, encoding: .utf8) {
print("Error string from server: \(errMsg)")
} else {
print("Error message from Alamofire: \(error.localizedDescription)")
}
}
guard let data = response.result.value else {
print("Unable to parse response data")
return
}
print("JSON from server: \(JSON(data))")
})

Resources