Missing argument for parameter #2 in call to Alamofire.request(URLRequestConvertible) - alamofire

Trying to pass an Authentication header in, using the recommended approach of a custom URLRequestConvertible.
So here is my URLRequestConvertible object that conforms to the protocol:
class SecureJSONRouter : URLRequestConvertible {
var type: String
var token: String
var parameters: [String: AnyObject]
init(typevar: String, tokenvar: String, parametersvar: [String: AnyObject]) {
type = typevar
token = tokenvar
parameters = parametersvar
}
var URLRequest: NSURLRequest {
let URL = NSURL(string: da_url)!
let URLRequesting = NSMutableURLRequest(URL: URL.URLByAppendingPathComponent(type))
let encoding = Alamofire.ParameterEncoding.JSON
URLRequesting.setValue(token, forHTTPHeaderField: "Authorization")
return encoding.encode(URLRequesting, parameters: parameters).0
}
}
It's basically a place to store a few things, like a bit of URL, and a token, and a way to create a NSURLRequest with a full URL, the JSON parameters, and the header field for authorization.
When I try to call it like this:
let myUrlRequest: URLRequestConvertible = SecureJSONRouter(typevar: "locations", tokenvar: token!, parametersvar: parameters)
Alamofire.request(myUrlRequest).response{ (req, resp, data, error) in
if (error != nil) {
println(req)
println(resp)
} else {
println("saved \(data)")
}
}
it won't compile, gives me a "Missing argument for parameter #2 in call" error, at the request line.
Any ideas?
PS: I did have my SecureJSONRouter thingy as the recommended Enum instead of a Class, but I got the same error. I was looking at the protocol definition, and figured there's no reason it can't be a simpler (class) in my case, so I changed it. Still the same error.

I think there's a few possible culprits here. First off, are you sure you're calling Alamofire and not AlamoFire? I've seen people make that mistake before.
As for the sample code you posted, it didn't compile for a few different reasons. I couldn't reproduce exactly the same compiler errors you were seeing, but here's a slightly modified version of you original post that does compile.
class SecureJSONRouter : URLRequestConvertible {
var type: String
var token: String
var parameters: [String: AnyObject]
init(typevar: String, tokenvar: String, parametersvar: [String: AnyObject]) {
type = typevar
token = tokenvar
parameters = parametersvar
}
var URLRequest: NSURLRequest {
let URL = NSURL(string: "http://httpbin.org")!
let URLRequesting = NSMutableURLRequest(URL: URL.URLByAppendingPathComponent(type))
let encoding = Alamofire.ParameterEncoding.JSON
URLRequesting.setValue(token, forHTTPHeaderField: "Authorization")
return encoding.encode(URLRequesting, parameters: parameters).0
}
}
Then here's an example of calling your SecureJSONRouter.
let token: String? = "my_fancy_token"
let parameters: [String: AnyObject] = ["sample_parameter": "sample_parameter_value"]
let myUrlRequest: URLRequestConvertible = SecureJSONRouter(typevar: "locations", tokenvar: token!, parametersvar: parameters)
Alamofire.request(myUrlRequest).response{ (req, resp, data, error) in
if (error != nil) {
println(req)
println(resp)
} else {
println("saved \(data)")
}
}
That is compiling with Xcode 6.1.1 against the Alamofire 1.1.3 release. Hope that helps!

Related

Swift SQL POST method - Why does it always create a response with <null> as the string?

I'm trying to set up POST requests to connect my Swift Project to my SQL server. I found a lot of good resources on how to create the POST requests, and my code seems to create the request fine. However, it always returns a null string instead of the desired output string. How can I get the request to submit with the correct string?
My POST function:
func addString() {
// declare the parameter as a dictionary that contains string as key and value combination. considering inputs are valid
let parameters: [String: Any] = ["textstring":"Testing..."]
// create the url with URL
let url = URL(string: "http://localhost:3000/strings")! // change server url accordingly
// create the session object
let session = URLSession.shared
// now create the URLRequest object using the url object
var request = URLRequest(url: url)
request.httpMethod = "POST" //set http method as POST
// add headers for the request
request.addValue("application/json", forHTTPHeaderField: "Content-Type") // change as per server requirements
do {
// convert parameters to Data and assign dictionary to httpBody of request
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
} catch let error {
print(error.localizedDescription)
return
}
// create dataTask using the session object to send data to the server
let task = session.dataTask(with: request) { data, response, error in
if let error = error {
print("Post Request Error: \(error.localizedDescription)")
return
}
// ensure there is valid response code returned from this HTTP response
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode)
else {
print("Invalid Response received from the server")
return
}
// ensure there is data returned
guard let responseData = data else {
print("nil Data received from the server")
return
}
do {
// create json object from data or use JSONDecoder to convert to Model struct
if let jsonResponse = try JSONSerialization.jsonObject(with: responseData, options: .mutableContainers) as? [String: Any] {
print(jsonResponse)
// handle json response
} else {
print("data maybe corrupted or in wrong format")
throw URLError(.badServerResponse)
}
} catch let error {
print(error.localizedDescription)
}
}
// perform the task
task.resume()
}
My Object TextString that emulates the SQL table (Table "strings" has two columns: "id" (SERIAL PRIMARY KEY) and "textstring" (VARCHAR(255))
struct TextString: Codable, Hashable, Identifiable {
var id: Int
var textString: String
enum CodingKeys: String, CodingKey {
case id = "string_id"
case textString = "textstring"
}}
My response output:
["string_id": 28, "textstring": <null>]
I'm thinking that the issue is with the serialization but the code is taken almost directly from a youtube video where the test cases are shown and they work. Does anyone know why the output returns "textstring" as null and not "Testing..."?
Thanks in advance!

Alamofire.download by post with parameters not working

Hello I am doing download file by post with parameters. But server can't receive post parameters.
But if i do same thing with get with url parameters. Everything works fine.
Almofire.request also works fine by post with parameters. But only Almofire.download by post with parameter does not work.
Why Alamofire.download does not send paramters by post method ??
var sourceStringURL : String = "\(tmp_url)download"
let destination: DownloadRequest.DownloadFileDestination =
{
_, _ in
let fileURL = URL(fileURLWithPath: destPath)
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
Alamofire.download(sourceStringURL, method: .post, parameters: ["id": idStr, "var": varStr], encoding: JSONEncoding.default, headers: nil, to: destination)
.downloadProgress
{
progress in
var tmpPercent : Int = Int(progress.fractionCompleted*100 / 1.0)
}
.response
{
response in
if let error = response.error
{
print(error)
}
else
{
//success
}
}
Server receives post request correctly with Retrofit library in Android.
I just found that if i change JSONEncoding.default to URLEncoding.default.
It works fine.

Formating json object into Array of dictionary in swift

let todoEndpoint: String ="http://localhost:16789/api/product"
guard let url = NSURL(string: todoEndpoint) else {
print("Error: cannot create URL")
return
}
let urlRequest = NSURLRequest(url: url as URL)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: urlRequest as URLRequest) {
(data, response, error) in
guard let responseData = data else {
print("Error: did not receive data")
return
}
guard error == nil else {
print("error calling GET")
print(error)
return
}
do{
self.users = try JSONSerialization.jsonObject(with: responseData, options: []) as? Array}
catch{
print("Error parsing")
}
}
task.resume()
this is my Output my API
[{"ProductId":2,"Category":"Laptop","Brand":"Apple","ModelName":"MacBook Pro","SerialNumber":"Test1","DatePurchased":"2016-08-12T00:00:00","EmployeeName":"Vismita Shetty","DateAssigned":"2017-01-17T00:00:00"},{"ProductId":4,"Category":"Keyboard","Brand":"Logitech","ModelName":"K200","SerialNumber":"TestKeyboard1","DatePurchased":"2017-01-23T03:02:13.247","EmployeeName":"Vismita Shetty","DateAssigned":"2017-01-17T00:00:00"},{"ProductId":5,"Category":"Keyboard","Brand":"Logitech","ModelName":"K200","SerialNumber":"testkeyboard2","DatePurchased":"2017-01-23T03:03:26.07","EmployeeName":"Suraj Pangam","DateAssigned":"2017-01-17T00:00:00"}]
What I currently trying to do convert user into different variable which will be of type Array of dictionaries in swift. So that Each object can be accessed by key. I want to make it generic so that even some properties got changed it won't matter as it won't be accessed by providing property name. Like (users[indexPath.row] as? [String: AnyObject])?["EmployeeName"] as! String!.
Instead if i make it to dictionary i will be easily do it by running for (key,value) loop for array of dictionary.

Get server response message from error

My server (CakePHP) is responding like so:
$this->response->statusCode('400');
$this->response->type('json');
$this->response->body(json_encode(array('message' => 'Bookmark already exists')));
The Postman output looks like what you would expect:
{"message":"Bookmark already exists"}
The problem is that I cannot find a way to access this message from the failure handler (Alamofire 3.1.3 + SwiftyJSON 2.3.2)
Alamofire.request(.POST...
.validate()
.responseJSON { response in
switch response.result {
case .Success(_):
// All good
case .Failure(let error):
// Status code 400
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result)
I cannot find a way to cast response.data to JSON as a I simply get nil and the result returns just FAILURE.
Is there a way to access this server message from the failure handler ?
The data is not parsed in the .Failure case per the Alamofire 3.0 migration guide. However, server data is still available in response.data and can be parsed.
Below should work to parse this manually:
Alamofire.request(.POST, "https://example.com/create", parameters: ["foo": "bar"])
.validate()
.responseJSON { response in
switch response.result {
case .Success:
print("Validation Successful")
case .Failure(_):
var errorMessage = "General error message"
if let data = response.data {
let responseJSON = JSON(data: data)
if let message: String = responseJSON["message"].stringValue {
if !message.isEmpty {
errorMessage = message
}
}
}
print(errorMessage) //Contains General error message or specific.
}
}
}
This uses SwiftyJSON which provides the JSON struct to convert NSData. Parsing NSData to JSON can done without SwiftyJSON, answered here.
Another cleaner option might be to write a Custom Response Serializer.
A method with the router and no SwiftyJSON:
Alamofire.request(APIRouter.Register(params: params)).validate().responseJSON { response in
switch response.result {
case .Success(let json):
let message = json["clientMessage"] as? String
completion(.Success(message ?? "Success"))
case .Failure(let error):
var errorString: String?
if let data = response.data {
if let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: String] {
errorString = json["error"]
}
}
completion(.Error(errorString ?? error.localizedDescription))
}
}
I have used the following lines to read the response body from a Alamofire request.
Alamofire.request(.POST, serveraddress, headers: headers, encoding: .JSON)
.response{ request, response, data, error in
let responseData = String(data: data!, encoding: NSUTF8StringEncoding)
print(responseData)
}
With this body I can get my custom server response errormessage.
best regards
For Alamofire 4.0 and above :
Try this
response.response?.statusCode
url : "YOUR-URL"
parameters: "YOUR PARAMETER DICTIONARY"
headers: "YOUR HEADER DICTIONARY"
I am using SwiftyJSON for JSON Parsing
A sample request is here :
func createPostRequestWith(path: String?,
parameters: [String : Any]? = nil,
success : #escaping (Any?) -> (),
failure : #escaping (NSError) -> ()) {
if !(Alamofire.NetworkReachabilityManager()?.isReachable)! {
let error = NSError(domain: "", code: -1003, userInfo: nil)
failure(error)
} else {
guard let url = path else { return }
Alamofire.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: createCurrentHeader()).validate(statusCode: 200..<300).responseJSON {
response in
switch response.result {
//Remove loader here either after parsing or on error
case .success(let data):
success(data)
case .failure(let error):
print(error)
if let responseData = response.data {
var parsedResponseData = JSON.init(data: responseData)
let customError = NSError(domain: parsedResponseData["message"].stringValue, code: response.response?.statusCode ?? 555, userInfo: nil)
failure(customError as NSError)
} else {
failure(error as NSError)
}
}
}
}
}

AlamoFire with Swift 1.2: Ambiguous use of 'responseJSON'

I'm attempting to use AlamoFire with Swift 1.2 in XCode 6.3. I've fixed most of the problems (i.e. changing as to as!) but I have one that I can't figure out.
The following code - and snippets like it - generates a compile time error with the message "Ambiguous use of 'responseJSON'" at the line 5 ("req.responseJSON(){"). What do I need to change in the AlamoFire library or my code to fix it? Note: I imported the project as described in the documentation and it worked fantastic in Swift 1.1 and XCode 6.1.1
func theaters(delegate:GlobalNetworkingDelegate){
if let url = self.mainNetworkingUrl{
var urlToUse = url + "theaters"
var req:Request = Alamofire.request(.GET, urlToUse, parameters: [:], encoding: .URL)
req.responseJSON(){
(req, response, jsonOut, error) in
if(response.statusCode == 200 && error == nil){
var ajson = JSON(jsonOut!)
delegate.globalTheatersOutomce!(true, json: jsonOut, error: error)
}
}
}
}
I have also gotten the following to work:
Alamofire.manager.request(.PUT, pathWithId(user.key), parameters: user.toDict(), encoding: .JSON)
.responseString( completionHandler: {
(request: NSURLRequest, response: NSHTTPURLResponse?, responseBody: String?, error: NSError?) -> Void in
if responseBody == "OK" {
completion(user, nil)
} else {
completion(nil, error)
}
})
i.e. by explicitly stating the parameter name of the closure instead of letting it trail after the method paranthesis. It seems that the new compiler has a problem identifying the method otherwise.
Separating the trailing closure into its own variable and then calling resonseJSON(closure) fixes the problem, but I'm not sure why. Anyone have a reason? Here is the working code:
func theaters(delegate:GlobalNetworkingDelegate){
if let url = self.mainNetworkingUrl{
var urlToUse = url + "theaters"
var req:Request = Alamofire.request(.GET, urlToUse, parameters: [:], encoding: .URL)
var aClosure = {(req:NSURLRequest, response:NSHTTPURLResponse?, jsonOut:AnyObject?, error:NSError?) -> Void in
if(response!.statusCode == 200 && error == nil){
var ajson = JSON(jsonOut!)
delegate.globalTheatersOutomce!(true, json: jsonOut, error: error)
}
}
req.responseJSON(aClosure)
}
}
If you wrap the closure in () instead of leaving it trailing it works also. It works for the same reason as the other answers here, just another way to write it.
func theaters(delegate:GlobalNetworkingDelegate){
if let url = self.mainNetworkingUrl {
var urlToUse = url + "theaters"
var req:Request = Alamofire.request(.GET, urlToUse, parameters: [:], encoding: .URL)
req.responseJSON({
(req, response, jsonOut, error) in
if(response.statusCode == 200 && error == nil){
var ajson = JSON(jsonOut!)
delegate.globalTheatersOutomce!(true, json: jsonOut, error: error)
}
})
}
}
I ran into the same issue. Updating your Alamofire to the latest version (1.2.2 as the time I wrote the answer) solved the problem for me.