I'm following Alamofire's CRUD and authorization section:
enum Router: URLRequestConvertible {
So what I want to accomplish is basically a simple PUT request which looks like this:
http://localhost:8080/rest/users/add?id=
So in my code I have:
let requestParam : [String : AnyObject] = ["id" : "\(SOMEID)"]
Alamofire.request(Router.AddUser(parameters: requestParam))
.validate()
.responseString { response in
switch response.result {
case .Success:
..
However, following my server doesn't get this id parameter.
Debugging the NSMutableURLRequest, I find that the id parameter isn't added.
case .AddUser(let parameters):
print(parameters)
let encodedURL = Alamofire.ParameterEncoding.URL.encode(mutableURLRequest, parameters: parameters).0
print (encodedURL)
Console output:
["id": 5649fec6d4c662c573d39fb4]
{ URL: http://localhost:8080/rest/users/add }
This is really strange, because I had another method written almost identically but I wasn't getting the same issue.
Edit:
It turns out after some trials that it's because the method is PUT. If it was GET method then parameters were added correctly. Does anyone know why I can't put request parameters for PUT? Is this intentional?
In your router, why don't you use NSURLComponents to build your url and then return NSMutableURLRequest like that:
enum Router: URLRequestConvertible {
...
var URLRequest: NSMutableUrlRequest {
var urlComponents = NSURLComponents()
urlComponents.host = // something
urlComponents.scheme = // probably wanna use https
switch self {
case .AddUser(let parameters):
// set urlComponents.path here
urlComponents.query = parameters.queryString
// depending on your code you may want to check before force unwrapping URL below
return NSMutableUrlRequest(URL: urlComponents.URL!)
}
}
}
then you can extend dictionary with a computed property of type String.
Hope that helps!
Related
We are facing the following networking error when the response is somehow large(14kb) on iOS 13.
[-1103] Error Domain=NSURLErrorDomain Code=-1103 "resource exceeds maximum size"
As we are using Alamofire, this problem is treated as error result which breaks our treatments of the results.
The strange thing is that if we use NSURLSession directly, though this error is still seen from logging, we don't actually receive it in the callback of
session.dataTask(with: request) { value, response, error in ... }
So the result can treated correctly.
This problem is never seen before. Anyone has got some idea on that ?
With the help of the Slack community, we find the answer is that
on iOS13, it is not allowed to add a body in GET request. To make it work again, we can either switch to a POST/PUT request or add body value via url parameters of the GET request.
Pass query parameters in GET request like the following:
let parameters: Parameters = [
"param": value
]
Alamofire.request(urlString, method: .get, parameters: parameters, encoding: URLEncoding.queryString)
I have face same issue and find out the solution.
You can't pass parameter in body while using GET.
Either use POST method if API support or pass it in URL like below.
AnyURL?Parameter=Value&Parameter=Value
Finally found the answer. For GET services I was trying to add an httpBody. Something like this:
do {
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
} catch let error {
errorCompletion(error)
return
}
The solution was just to add an if to avoid that chunk of code if httpMethod is a GET. Seems like an iOS 13 new behavior and the error message given by Swift definitely not helps at all
Alamofire: You should try this!
Alamofire.request(urlString, method: .get, parameters: parameters, encoding: URLEncoding.queryString)
Just avoid the httpBody for the GET API request.
if requestType != .get{
request.httpBody = data
}
#OR
For GET request append parameter into URL instead of the HTTP body
Use the below extension to create a query parameter from the dictionary.
extension NSObject {
func buildQueryString(fromDictionary parameters: [String:String]) -> String {
var urlVars = [String]()
for (var k, var v) in parameters {
let characters = (CharacterSet.urlQueryAllowed as NSCharacterSet).mutableCopy() as! NSMutableCharacterSet
characters.removeCharacters(in: "&")
v = v.addingPercentEncoding(withAllowedCharacters: characters as CharacterSet)!
k = k.addingPercentEncoding(withAllowedCharacters: characters as CharacterSet)!
urlVars += [k + "=" + "\(v)"]
}
return (!urlVars.isEmpty ? "?" : "") + urlVars.joined(separator: "&")
}
}
I used default url encoding instead of default json encoding and it's worked for me.
Alamofire.request(url, method: .get, parameters: param, encoding: URLEncoding.default)
OR
If you using URLRequestConvertible
enum NetworkRouter: URLRequestConvertible {
case someCase(lang:String)
var method: HTTPMethod {
return .get
}
var parameters: Parameters? {
switch self {
case .someCase(let param):
return ["lang": param.lang]
default:
return nil
}
}
var url: URL {
switch self {
case .someCase(let param):
return URL(string: Constants.baseURL + Constants.endPoint)!
default:
return URL(string: Constants.baseURL)!
}
}
var encoding: ParameterEncoding {
return URLEncoding.default
}
func asURLRequest() throws -> URLRequest {
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = method.rawValue
return try encoding.encode(urlRequest, with: parameters)
}
}
I got that issue because i pass empty parameters in Alamofire when send get request. So, instead of sending empty parameters i simply replace it for nil.
My fix is I only set .parameters to nil, then everything works fine. Because in Swift it still initialize the value of .parameters.
self.request.parameters = nil
Here you might have missing the method of the URL request that you are passing to data task. You have to add POST/PUT/DELETE to the URL request method parameter like below.
var request: URLRequest = URLRequest(url: SOME_VALID_URL)
request.body = SOME_VALID_DATA_IN_BYTES
request.method = "post" --> You are missing this.
I only see this issue when I build with Xcode 11. If I revert back to Xcode 10.3 I do not have the same issue anymore. While not a forever fix, if you're needing to push out code you can revert until you have time to fix it.
I'm a beginner in Swift. I'm trying to create an application using PUBG api. I add my headers using Alamofire. I have a text field on my storyboard , I enter my nickname there and get the data from pubg api. My problem is Alamofire adds "&" sign to front of parameters so this crashes the url. How can I prevent Alamofire to put "&" sign to parameter?
let playerURL = "https://api.pubg.com/shards/pc-eu/players?filter[playerNames]"
func findPlayer(playerName:String){
let httpParameters : Parameters = ["":playerName]
Alamofire.request(playerURL,method:.get,parameters:httpParameters,encoding:URLEncoding.default,headers:httpHeaders).responseJSON{response in switch response.result{
case .success(let value):
let response = JSON(value)
print(response["data"])
case .failure(_):
return
}
}
}
URL should be like this:
https://api.pubg.com/shards/pc-eu/players?filter%5BplayerNames%5D=PlayerName
Instead it becomes this:
https://api.pubg.com/shards/pc-eu/players?filter%5BplayerNames%5D&=PlayerName
If you're using Alamofire to encode the parameters, then you need to let it encode the parameters:
let playerURL = "https://api.pubg.com/shards/pc-eu/players"
....
let httpParameters : Parameters = ["filter[playerNames]": playerName]
...
My entire test case is as follows:
Create a blank one-view project
In AppDelegate add:
let playerURL = "https://api.pubg.com/shards/pc-eu/players"
func findPlayer(playerName:String){
let httpParameters : Parameters = ["filter[playerNames]": playerName]
let request = Alamofire.request(playerURL,
method:.get,
parameters:httpParameters)
print(request)
}
In application(_:didFinishLaunchingWithOptions:) add:
findPlayer(playerName: "PLAYERNAME")
Run
Output:
GET https://api.pubg.com/shards/pc-eu/players?filter%5BplayerNames%5D=PLAYERNAME
AlamofireImage seems to be supposed to request with GET method in general. But in our project, to download images we have to request with POST method, because we send access token. I have searched for the similar question in Stack Overflow, but I couldn't find enough answers. Does anyone know how to download with POST request?
The URL is as follow:
https://host_name/project_name/GetImage
You can use af_setImage method from AlamofireImage extension of UIImageView and pass any URLRequestConvertible parameter. For example, create URLRequest instance with Alamofire initializer:
let urlPath = "https://host_name/project_name/GetImage"
if var imageRequest = try? URLRequest(url: urlPath, method: .post) {
imageRequest.addValue("token", forHTTPHeaderField: "token_field")
imageView.af_setImage(withURLRequest: imageRequest)
}
Because We have to send parameters in HTTPBodyData, following the Loe's answer, I made some changes to our code. The following is our new code:
let urlPath = "https://host_name/project_name/GetImage"
let parameters:[String: Any] = [
"token": "tokenValue",
"imageName": "imageName"
]
let dataRequest = Alamofire.request(urlPath,
method: HTTPMethod.post,
parameters: parameters,
encoding: JSONEncoding.default,
headers: [:])
guard let imageRequest = dataRequest.request else {
return
}
imageView.af_setImage(withURLRequest: imageRequest)
The Point is first, we create a DataRequestobject and then convert it to URLRequest Type with Alamofire.request()method.
I am using Alamofire library for REST API calls. I have a Request Body of type
Dictionary(String, Any). There are few objects in the Request Body that are common for some APIs.
For eg: 1st API call contains following parameters in the request body.
var hotel = HotelParameter()
var food = foodParameter()
var address = addressParameter()
class RequestParameters: NSObject{
func parameter() -> NSDictionary {
var parameter : [String : Any] = [:]
parameter["hotels"] = hotel.params()
parameter["foodType"] = food.params()
parameter["address"] = address.params()
return parameter as! NSDictionary
}
Now in 2nd API call I have to pass only "hotels" and "address" in the RequestParameter.
My problem is: How to add or remove any extra parameter in the Alamofire Request Body?
Since I cannot add Request Body for 'n' number of Requests, there has to be a single RequestParameter which will get modified according to the api calls. There can be extra or single Parameter(s) in the Body.
Mostly "hotels" will be a common parameter for all Request Body.
I have tried a lot to solve this, But I get exception because it cannot parse some JSON response.
I have created functions to hit the api calls and I am passing the parameters like this.
var requestParam = RequestParamters()
Alamofire.request(url,
method: .post,
parameters: requestParam.parameter(),
encoding: JSONEncoding.default, headers: headers)
.responseJSON(completionHandler: { (data : DataResponse<Any>) in
I am not sure, I got your requirement right. But as per my understanding, you have to hit one API multiple times, and the parameter shall be different every time. So just write a method which'll take parameter as a method argument. Here is the sample code as per your requirement.
func getAllHotels(_ params:Dictionary, callback:#escaping (Dictionary<String, Any>, Error?)->Void)
{
let parameters: Parameters = params
Alamofire.request(baseUrl + "/getHotels", method: .post,parameters: parameters, encoding: URLEncoding.default).responseJSON { response in
debugPrint("All Response from API: \(response)")
switch response.result
{
case .success(let value):
callback(value as! Dictionary, nil)
case .failure(let error):
callback([:], error)
}
}
}
/** Now call the above method with your required parameters **/
I found out Two ways to do it.
Create an addExtraParams :[String : Any] = : type of Dictionary and add the key : value pair you need in this.
Create Requests functions for respective apis and just update the value of the required parameters using the object you get after logging.
For eg:
var user = response.object as! Person
var request = RequestParameters()
request.hotel.name = user.hotel_name
Update the values before the Alamofire request in the function that you have created.
I'm doing the migration of my app on Swift 2.0. I took the opportunity to also migrate Alamofire from 1.3 to 2.0.
But now my app is not working anymore, and i got many errors on the file where i use Alamofire.
First on my enum Router declaration i got an error who say
private enum Router: URLRequestConvertible {
EDIT: Here is the beginning of the methods that implement
URLRequestConvertible
// MARK: URLRequestConvertible
var URLRequest: NSURLRequest {
let URL = Router.baseURL.URLByAppendingPathComponent(self.path)
let URLRequest = NSMutableURLRequest(URL: URL)
URLRequest.HTTPMethod = self.method.rawValue
switch self {
case .Login(let email, let password):
return self.encoding.encode(URLRequest, parameters: [
"email": email,
"password": password]).0
case .Logout:
return self.encoding.encode(URLRequest, parameters: nil).0
}
Type 'Router' does not conform to protocol 'URLRequestConvertible'
Second in all my request when i'm gonna check the .responseJSON { (_, _, json, error) in i got an error who say
Tuple types '(NSURLRequest?, NSHTTPURLResponse?, Result)' (aka
'(Optional, Optional, Result)') and '(_, _, _, _)' have a different
number of elements (3 vs. 4)
EDIT: Ok no more error field but how do you do your error handling so ?
EDIT2: Ok got it now you need do use a switch for the Result. Thx
Error that i didn't had before
Thanks for your help !
For the second error refer to the Alamofire page here https://github.com/Alamofire/Alamofire
As you can see they changed the .responseJSON which now returns just 3 parameters. In version 1.3 there were 4 parameters instead. Basically you simply have to delete the error field in this way
.responseJSON { (_, _, json) in
I think you need to return 'NSMutableURLRequest' instead of 'NSURLRequest' if you havent changed that already.