Alamofire router modify path parameter - ios

I would like to do something like this using Alamofire 4 router.
case .updateUser(_):
return Constants.Routes.URL_USER_FRAG + "/(id)"
func asURLRequest() throws -> URLRequest {
case .updateUser(let parameters):
urlRequest = try URLEncoding.default.encode(urlRequest, with: parameters)
urlRequest.addValue("XMLHttpRequest", forHTTPHeaderField: "X-Requested-With")
}
In the asURLRequest, I want to set the value of (id) from parameters like urlRequest.path.id = parameters.id
Is this a possibility with Alamofire?

Related

Alamofire error request with parameter without name

I'm getting an error while trying to encode a parameter into a request url.
Here is my function to get the request url:
func asURLRequest() throws -> URLRequest {
let url = try baseURL.asURL().appendingPathComponent(path)
var request = URLRequest(url: url)
request.method = method
if method == .get {
request = try URLEncodedFormParameterEncoder().encode(parameters, into: request)
} else if method == .post {
request = try JSONParameterEncoder().encode(parameters, into: request)
request.setValue("application/json", forHTTPHeaderField: "Accept")
}
return request
}
It is working when the parameter is a dictionary like ["id": 1]. The url would be:
http://.../api/v1/items/?id=1
I want to pass the parameter 1 only, so the url would be like this:
http://.../api/v1/items/1
But it doesn't work, I get this error from Alamofire:
requestRetryFailed(retryError:
Alamofire.AFError.requestRetryFailed(retryError:
Alamofire.AFError.parameterEncoderFailed(reason:
Alamofire.AFError.ParameterEncoderFailureReason.encoderFailed(error:
Alamofire.URLEncodedFormEncoder.Error.invalidRootObject("string("1")")))
What you want is a path encoding, not a query encoding or form encoding. There is no specific parameter encoder in Alamofire for path components (though there is an ongoing feature request). Usually people encode them into the path directly, so you can modify your code to do so directly by using a router and having each route encode its own parameters.
func encodeParameters(into request: URLRequest) throws -> URLRequest {
switch self {
case .someRoute(parameters):
return try URLEncodedFormParameterEncoder().encode(parameters, into: request)
case .pathParameterRoute(parameter):
var request = request
request.url?.appendPathComponent(parameter)
return request
}
}

-1103 Error Domain=NSURLErrorDomain Code=-1103 "resource exceeds maximum size" iOS 13

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.

How to prevent alamofire to put "&" sign to front of parameter

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

Add GET parameter in request adapter of Alamofire

I am trying in the Request Adapter of Alamofire to add a GET parameter. However in the request adapter I am only able to add HTTPHeader fields.
Currently my request adapter looks like:
// MARK: - RequestAdapter
func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
if let url = urlRequest.url, url.lastPathComponent.hasPrefix(baseURLString) {
var urlRequest = urlRequest
// Want to inject param here
// e.g. urlRequest.addParam(param: "session", value: sessionToken")
return urlRequest
}
return urlRequest
}
I have a Router configured for the Paths but since I want my AuthHandler to be responsible to all Authentication related stuff I want to inject my sessionToken. This makes sure, together with RequestRetrier that any HTTP 401 related error is dealt with.
What is the best way to change the urlRequest?
Can you try
let params: Parameters = ["session": sessionToken]
return URLEncoding.default.encode(urlRequest, with: params)
(or)
return URLEncoding.queryString.encode(urlRequest, with: params)
Thanks
Sriram

Alamofire url encoded request parameter not getting added

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!

Resources