I am trying to make an alamofire post request, I am sending a parameter and a body , as following:
static func sendFeedbackResultOldCustomer(customerId: String?,fbackAnswers:String? ,answers: String?, completion: #escaping (Bool , String?) ->() ){
let parameters: Parameters = ["customer_id":customerId!,"customer_new":"0","x-session":getXSession()]
request(urlString: APIStrings.feedbackSent, parameters: parameters, method: .post, headers: nil, encoding: answers, updateXsession: false) { (success, error, errorMsg, response) in
if(success) {
completion(true, nil)
}
else {
completion(false, response?.result.error as? String)
}
}
}
the request code:
fileprivate static func request (urlString: String!, parameters: Parameters?, method: HTTPMethod, headers: HTTPHeaders?,encoding: String!, updateXsession: Bool, completion: #escaping(Bool, Error?, String?, DataResponse<Any>?) ->()) {
Alamofire.request(urlString, method: method, parameters: parameters, headers: headers,encoding:encoding).responseJSON { (response) in// here is the error (extra argument method in call)
let contentType = response.response?.allHeaderFields["X-Session"] as? String
if (updateXsession)
{
UserDefaults.standard.set(contentType, forKey: "x-session")
}
let success = checkIfSuccess(response: response)
if(success){
completion(success, nil, nil, response)
} else {
completion(success, response.error, "Failed", nil)
}
}
in the alamofire request, im getting the following error : Extra argument in call. any idea whats going on?
parametes im sending:
let parameters: Parameters = ["customer_id":customerId!,"customer_new":"0","x-session":getXSession()]
body im trying to send:
X_types = [{"type_id":"17","value":"3"},{"type_id":"12","value":"test"},{"type_id":"14","value":"4"},{"type_id":"19","value":"3"},{"type_id":"16","value":"4"},{"type_id":"13","value":"3"},{"type_id":"18","value":"4"},{"type_id":"15","value":"4"},{"type_id":"2","value":"4"},{"type_id":"11","value":"1"},{"type_id":"1","value":"3"},{"type_id":"8","value":"3"},{"type_id":"6","value":"2"},{"type_id":"4","value":"22-09-2017 - 12:1"},{"type_id":"5","value":"Test"}]
X_types is been sent in the encoding , as a string (x_types is as string type)
The signature for alamofire request is: public func request(_ url: URLConvertible, method: Alamofire.HTTPMethod = default, parameters: Parameters? = default, encoding: ParameterEncoding = default, headers: HTTPHeaders? = default). I think you have mismatched the signature.
Try
let request = Alamofire.request(url, method: HTTPMethod.post, parameters: params, encoding: JSONEncoding.default, headers: header)
request.responseJSON { response in
}
Related
i'm trying to have a system where all my api requests path through one function and map them to the corresponding object
func sendApi<T>(url : String , httpMethod : HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil , callbackSuccess : #escaping (T) -> () , callbackFailure : #escaping (T) -> ()) where T : Mappable {
Alamofire.request(url, method: httpMethod, parameters: parameters , encoding: encoding, headers: headers).responseObject{(response: (DataResponse<T>))in
switch response.result {
case .success :
let result = Mapper<T>().map(JSONObject: response.value)!
callbackSuccess(result)
break;
case .failure(let error):
if((error as NSError).code == ErrorResponse.noInternetConnection){
// errorCallBack(ErrorResponse.noInternetConnectionString)
}
// errorCallBack(error.localizedDescription)
print(error.localizedDescription)
break;
}
}
}
but when i try to call the function inside a get method for example
func testApiGet(url: String , packageId : Int ,callback :#escaping (myObject) -> Void , errorCallBack : #escaping (String) -> Void ){
let token = spm.getUserToken()
let headers = ["X-Auth-Token" : token]
let newUrl = url + "?packageId=" + String(packageId)
sendApi(url: url, httpMethod: HTTPMethod.get , parameters: nil, encoding: JSONEncoding.default, headers: headers, callbackSuccess: {(jsonObject) in
} , callbackFailure:{ (jsonObject)in
})
}
i get the error "Generic parameter 'T' could not be inferred"
of course i can set the type of the object
(response: (DataResponse<myObject>)
and the error will go.
my question is how solve this error to make it fully generic
It does not make sense that your error handler and your success handler have the same type T: Mappable. You are only going to get a mapped object in the success handler. The error handler should be something like (Error) -> ().
Secondly your function is generic with respect to the parameter type of the closure arguments, but when you are calling the function you are not specifying the type:
sendApi(url: url, httpMethod: HTTPMethod.get , parameters: nil, encoding: JSONEncoding.default, headers: headers, callbackSuccess: {(jsonObject) in
} , callbackFailure:{ (jsonObject)in
})
The compiler therefore has no idea what type you are expecting and thats why its complaining that it cannot infer the type here. You need to explicitly provide the parameter type because that is what determines what version of the generic gets invoked:
sendApi(url: url, httpMethod: HTTPMethod.get , parameters: nil, encoding: JSONEncoding.default, headers: headers, callbackSuccess: {(jsonObject: MyMappableType) in
} , callbackFailure:{ (error: Error)in
})
I need to send a request to a server and get a response.
I have the following URL:
http://192.168.200.10:9044/api/tables/?filter={"open_visible":true,"related":false}
For the query I'm using Alamofire. Here are some ways how I do it:
1)
class func getTables(completion: #escaping (_ response : DataResponse<TablesResponse>) -> Void) {
SVProgressHUD.show()
let getTablesPath = apiEntryPoint + "tables/?filter={\"open_visible\":true,\"related\":false}"
Alamofire.request(getTablesPath)
.validate()
.responseObject { (response: DataResponse<TablesResponse>) in
SVProgressHUD.dismiss()
completion(response)
}
}
I get the error: screenshot
2)
class func getTables(completion: #escaping (_ response : DataResponse<TablesResponse>) -> Void) {
SVProgressHUD.show()
let getTablesPath = apiEntryPoint + "tables/?filter={%22open_visible%22:true,%22related%22:false}"
Alamofire.request(getTablesPath)
.validate()
.responseObject { (response: DataResponse<TablesResponse>) in
SVProgressHUD.dismiss()
completion(response)
}
}
I get the error.
3)
class func getTables(completion: #escaping (_ response : DataResponse<TablesResponse>) -> Void) {
SVProgressHUD.show()
var getTablesPath = apiEntryPoint + "tables/?filter="
let jsonParameters = ["open_visible":true, "related":false]
if let json = try? JSONSerialization.data(withJSONObject: jsonParameters, options: []) {
if let content = String(data: json, encoding: .utf8) {
getTablesPath += content
}
}
Alamofire.request(getTablesPath)
.validate()
.responseObject { (response: DataResponse<TablesResponse>) in
SVProgressHUD.dismiss()
completion(response)
}
}
I get the error.
4)
class func getTables(completion: #escaping (_ response : DataResponse<TablesResponse>) -> Void) {
SVProgressHUD.show()
let getTablesPath = apiEntryPoint + "tables/"
Alamofire.request(getTablesPath, parameters: ["open_visible":true, "related":false])
.validate()
.responseObject { (response: DataResponse<TablesResponse>) in
SVProgressHUD.dismiss()
completion(response)
}
}
I got all tables. Without taking into account the desired parameters. It's bad.
QUESTION
As I can send a request for the server, considering the necessary parameters.
Try
let urlParameters = yourParametersString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
because you can't just pass { and } characters in URL
You can use request parameter for more user-friendly.
Put your all request data into NSDictionary and send it to the server.
let parameters: NSDictionary = [
"YOUR_KEY": YOUR_VALUE,
]
// Both calls are equivalent
Alamofire.request(YOUR_SERVER_ULR, method: .post, parameters: parameters, encoding: JSONEncoding.default)
Alamofire.request(YOUR_SERVER_ULR, method: .post, parameters: parameters, encoding: JSONEncoding(options: []))
Another way is that, if you are passing some special character into your question parameter then you have encoded the URL.
let URL = YOUR_FINAL_URL_TO_SERVER.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
You can check out Apple Document for more detail.
I use Alamofire for my request in this function and I have this error if someone could help me please thank in advance.
Expression type 'DataRequest' is ambiguous without more context
func report(_ track: Track, completionHandler: #escaping (_ error: NSError?) -> Void) {
var headers:[String:String] = [:]
if AuthManager.defaultAuthManager().isLoggedIn() {
headers = ["Authorization": "Bearer " + AuthManager.defaultAuthManager().authToken.token!]
}
let params: [String: Any] = ["trackCode": track.code]
let urlString = Cizoo.APIBaseUrl + CizooScheme.report
CizooAPI.manager.request(urlString, method: .post, parameters: params, encoding: .JSONEncoding.default, headers: headers as HTTPHeaders)
.validate()
.responseJSON(completionHandler: { // Error at this line
response in
switch response.result {
case .success:
completionHandler(error: nil)
case .failure(let error):
completionHandler(error: error)
}
})
}
From the Alamofire source code you can see that the declaration of the method is:
#discardableResult
open func request(
_ url: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil)
-> DataRequest
{
var originalRequest: URLRequest?
do {
originalRequest = try URLRequest(url: url, method: method, headers: headers)
let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
return request(encodedURLRequest)
} catch {
return request(originalRequest, failedWith: error)
}
}
Which in your case probably the urlString is not conforming to the URLConvertible protocol.
Thanks !
Finally, It was a concern of type declaration
Here is the code solved :
func report(_ track: Track, completionHandler: #escaping (_ error: NSError?) -> Void) {
var headers:HTTPHeaders? = [:]
let params:Parameters? = ["trackCode": track.code]
let encoding:ParameterEncoding = JSONEncoding.default
let method:HTTPMethod = .post
let urlString:URLConvertible = (Cizoo.APIBaseUrl + CizooScheme.report)
if AuthManager.defaultAuthManager().isLoggedIn() {
headers = ["Authorization": "Bearer " + AuthManager.defaultAuthManager().authToken.token!]
}
CizooAPI.manager.request(urlString, method: method, parameters: params, encoding: encoding, headers: headers)
.validate()
.responseJSON(completionHandler: {
response in
switch response.result {
case .success:
completionHandler(nil)
case .failure(let error):
completionHandler(error as NSError?)
}
})
}
I have began to refactor my Alamofire api calls to keep them in a seperate file. The only problem is that I dont know how to return the statuscode as well.
Api file:
static func getCategories(_ catId: Int, response: #escaping (JSON) -> ()) {
let urlString = baseURL + ResourcePath.categories(catId: catId).description
Alamofire.request(urlString, encoding: JSONEncoding.default, headers: headers).responseJSON{ (responseData) -> Void in
let cCatData = JSON(responseData.result.value ?? [])
response(cCatData)
}
}
Then in my VC:
Api.getCategories(catId) { (JSON) -> () in
self.categories = JSON["catData"]
self.tableView.reloadData()
}
But I need to know if the status code is 200/400/404/422/500 and I dont want to use the .validate() function, I want to pass the status code
Normally if I would have everything in the same file I would get the status code by:
Alamofire.request("https://www.something", parameters: parameters, encoding: JSONEncoding.default, headers: headers)
.responseJSON() { response in
if let statusCode = response.response?.statusCode {
if statusCode == 200 {
}
}
If you want your closure to pass back the status code, then add an Int? parameter and pass it back:
static func getCategories(_ catId: Int, response: #escaping (JSON, Int?) -> ()) {
let urlString = baseURL + ResourcePath.categories(catId: catId).description
Alamofire.request(urlString, encoding: JSONEncoding.default, headers: headers).responseJSON { responseData in
let cCatData = JSON(responseData.result.value ?? [])
response(cCatData, responseData.response?.statusCode)
}
}
Or I might use more standard variable/parameter names:
static func getCategories(_ catId: Int, completionHandler: #escaping (JSON, Int?) -> ()) {
let urlString = baseURL + ResourcePath.categories(catId: catId).description
Alamofire.request(urlString, encoding: JSONEncoding.default, headers: headers).responseJSON { response in
let cCatData = JSON(response.result.value ?? [])
completionHandler(cCatData, response.response?.statusCode)
}
}
Either way, you can then do:
Api.getCategories(catId) { json, statusCode in
guard statusCode == 200 else {
print("status code not 200! \(statusCode)")
return
}
// if you got here, the status code must have been 200
}
So basically you want is something like this:
func returnStatusCode(_ urlPath: String, parameters: [String: AnyObject]? = nil, headers: [String: String]? = nil, encoding: ParameterEncoding = URLEncoding.default, completion: #escaping (_ statusCode: Int, _ responseData: [String: AnyObject]?) -> Void) {
// you can omit 'encoding:' if you'll set it to default since it will be default by default. \o/
Alamofire.request(urlPath, method: .get, parameters: parameters, encoding: encoding, headers: headers).responseJSON { (response) in
if response.result.isSuccess, let returnObject = response.result.value as? [String: AnyObject], let statusCode = response.response?.statusCode {
// do something...
completion(statusCode, returnObject)
}
}
}
use the callback to handle the status code alone
I have this class defined in my app to handle requests to my backend
class BackendService {
// Retrieves user chat channels
class func getChatChannels(success:(response: Response)->(), failure: (response:Response)->()) {
let chatsURL = baseURL + "/chats"
performRequestWith(success, failure: failure, url: chatsURL, parameters: nil)
}
func performRequestWith(success:(response: Response)->(), failure: (response: Response) -> (), url: String, parameters: String?) {
var manager = Alamofire.Manager.sharedInstance
let keychain = Keychain(service:"com.domain.app")
let token = keychain.get("token")
if let token = token {
manager.session.configuration.HTTPAdditionalHeaders = ["Authorization": "Bearer \(token)"]
manager.request(.GET, url, parameters:nil).responseJSON { (req, res, json, err) in
if(err != nil) {
var response = Response()
response.error = err
failure(response: response)
} else {
var response = Response()
if let httpStatus = HTTPStatus(rawValue: res!.statusCode) {
response.httpStatus = httpStatus
}
response.payload = JSON(json!)
success(response: response)
}
}
}
}
}
I am trying to pass the callback/closure arguments that getChatChannels receives to performRequestWith. In performRequestWith(success, failure: failure, url: chatsURL, parameters: nil) I am getting Extra argument 'failure' in call
I have little experience with Swift and I am clearly doing something awfully wrong here. Some help would much appreciated.
There is no issue with your method calling code.
The issue is you are calling a instance method from a class method.
Either you should change both methods to class method, like:
class func getChatChannels(success:(response: Response)->(), failure: (response:Response)->())
{
let chatsURL = baseURL + "/chats"
performRequestWith(success, failure: failure, url: chatsURL, parameters: nil)
}
class func performRequestWith(success:(response: Response)->(), failure: (response: Response) -> (), url: String, parameters: String?)
{
// Your code
}
or Change both to instance method, like:
func getChatChannels(success:(response: Response)->(), failure: (response:Response)->())
{
let chatsURL = baseURL + "/chats"
performRequestWith(success, failure: failure, url: chatsURL, parameters: nil)
}
func performRequestWith(success:(response: Response)->(), failure: (response: Response) -> (), url: String, parameters: String?)
{
// Your code
}
Another option is create an instance of the class inside the class method and using that call the instance method.