Alamofire dealing with special character parameters - swift

the ServiceKey I got for the api is mixed with complex characters, like D%2FFgugDIl1le9xiY7be1ge%2B0Q%3D%3D
and when I put the key in the params of alamofire and use the .get keyword, my key transforms and when the url is actually created, it becomes a totally different key.
is there any way to solve this problem?
This is the code I am using
Alamofire.request(BusURL, method: .get, parameters: ["cityCode": 25, "routeId":"DJB30300052ND", "ServiceKey": key])
.responseString { response in
print(" - API url: \(String(describing: response.request!))") // original url request
var statusCode = response.response?.statusCode
switch response.result {
case .success:
print("status code is: \(String(describing: statusCode))")
if let string = response.result.value {
print("XML: \(string)")
}
case .failure(let error):
statusCode = error._code // statusCode private
print("status code is: \(String(describing: statusCode))")
print(error)
}
}

Try below:
let params = ["cityCode": "25", "routeId":"DJB30300052ND"]
var urlParams = params.flatMap({ (key, value) -> String in
return "\(key)=\(value)"
}).joined(separator: "&")
let key = "&ServiceKey=D%2FFgugDIl1le9xiY7be1ge%2B0Q%3D%3D"
urlParams.append(key)
let url = "https://google.com?\(urlParams)"
print("url\(url)")
Alamofire.request(url, method: .get).validate().responseString(completionHandler: {response in
switch response.result{
case .success:
let s = response.result.value ?? "Empty Result"
print("response \(s)")
case .failure:
print("Call Failed")
debugPrint(response)
}
})
output: https://google.com?cityCode=25&routeId=DJB30300052ND&ServiceKey=D%2FFgugDIl1le9xiY7be1ge%2B0Q%3D%3D

Related

Swifui print value of data in response

I am using a post API method like this
AF.request("http://40.86.255.119/api/Authentication", method:.post, parameters: parameters,encoding: JSONEncoding.default) .responseJSON { (response) in
print(response)
}
It's showing me a response
success({
data = {
security = (
);
token = "eyJhbGc";
};
key = "<null>";
message = "Login Successfully";
succeed = 1;
})
I need to print just a token of data and need to know how can I do this?
Response screenshot by swagger
I try to like this but the issue is how ill show token that is inside the data array. It's showing a message which is outside an array but the token is inside an array.
AF.request("http://40.86.255.119/api/Authentication", method: .post, parameters: parameters, encoding: JSONEncoding.default)
.responseJSON { response in
switch response.result {
case .success(let value):
if let json = value as? [String: Any] {
print(json)
print(json["message"]) //this work
print(json["data"]["token"]) //this didnt work
}
case .failure(let error):
print(error)
}
}
I highly recommend to take advantage of the JSON decoding capabilities of AF.
Create two structs
struct Response : Decodable { let data : TokenData }
struct TokenData : Decodable { let token : String }
And replace .responseJSON with .responseDecodable and an appropriate type annotation of response.
In any case you should handle the potential error
AF.request("http://40.86.255.119/api/Authentication", method:.post, parameters: parameters) .responseDecodable { (response : DataResponse<Response,AFError>) in
switch response.result {
case .success(let result): print(result.data.token)
case .failure(let error): print(error)
}
}

'Invalid type in JSON write (UIImage)' Alamofire API request

i am trying to send an image to an api using alamofire heres what i got:
var uploadedProfileImage: UIImage = UIImage()
let body: Parameters = [
"profilePic": uploadedProfileImage,
"name": "John Doe"
]
Alamofire.request(BASE_URL",method: .post,parameters: body,encoding: JSONEncoding.default).responseData { response in
debugPrint("All Response Info: \(response)")
if let data = response.result.value, let utf8Text = String(data: data, encoding: .utf8) {
print("Data: \(utf8Text)")
}
}
so this is the code i am using uploadProfileImage has an image that the user picked from the library and my api receives a json body parameter in which it has profilePic which is off type file when i run this its giving me an error saying 'Invalid type in JSON write (UIImage)'.theres is also a terminating with uncaught exception of type NSException error. what am i doing wrong and how to fix it?
You can't upload image with
"profilePic": uploadedProfileImage
as it's used for types that are encode-able such as strings , you need
upload image to server using Alamofire
func uploadImageAndData(_ url:String,parameters1:Parameters,headers1:HTTPHeaders,images:[UIImage]){
Alamofire.upload(multipartFormData: { multipartFormData in
// import image to request
var i=0
for imageData in images {
// multipartFormData.append(self.resizeImage(image: imageData, targetSize: CGSize(width: 400, height:
multipartFormData.append(imageData.pngData()!, withName: "image", fileName: "image"+".jpeg", mimeType: "image/jpeg")
i += 1
}
for (key, value) in parameters1 {
multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
}
} ,to: url,method:.post,
headers:[:],
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (Progress) in
print("Upload Progress: \(Progress.fractionCompleted)")
//SwiftSpinner.show(progress: Progress.fractionCompleted*100, title: "تحميل")
})
upload.responseJSON { response in
switch response.response?.statusCode {
case 200 :
break
case 400 :
break
case 401 :
break
case 302 :
break
case 500 :
break
default: break
}
}
return
case .failure(let encodingError):
}
})
}
var head = [String:Any]()
head["Accept"]="application/json"
head["Authorization"] = "Bearer \(tokenIfExists)"

Alamofire request body nil when uploading image using multipartFormData

I seem to have a problem regarding image upload and passing parameters using Alamofire. I have a quite simple function for multipart data which looks like:
sessionManager.upload(multipartFormData: { (multipartFormData) in
for (key, value) in parameters {
print("\(value)")
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
multipartFormData.append(UIImagePNGRepresentation(image)!, withName: "document", mimeType: "image/png")
}, to: baseURL + "/documents", encodingCompletion: { (result) in
switch result{
case .success(let upload, _, _):
upload.validate().responseJSON { response in
print("Succesfully uploaded")
}
case .failure(let error):
print("Error in upload: \(error.localizedDescription)")
}
})
I have OAuth2Handler which i've implemented for headers and authorisation and it works for all other requests. I have also tried to implement this without wrapper using Alamofire object directly but still no luck. When I inspect the request i notice that httpBody is always nil, which corresponds to error I get from the server and the message says that I do not pass required parameters.
This is Working for me Swift 4
func callPostApiImage(api:String, parameters:[String:AnyObject]?,image:UIImage,Name:String, mime_type:String = "image/jpg", complition:#escaping (AnyObject)->Void){
// Encode Data
let base64EncodedString = toBase64EncodedString(toJsonString(parameters: parameters!))
let File_name = "image_" + String(arc4random()) + ".jpg"
Alamofire.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(UIImageJPEGRepresentation(image, 0.5)!, withName: Name, fileName: File_name, mimeType: mime_type)
multipartFormData.append(base64EncodedString.data(using: String.Encoding.utf8)!, withName: "jsondata")
}, to:api){ (result) in
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (progress) in
print(progress)
})
upload.responseJSON { response in
print(response.result)
}
case .failure(let encodingError):
print("",encodingError.localizedDescription)
break
}
}
}
// Base64EncodedString
func toBase64EncodedString(_ jsonString : String) -> String
{
let utf8str = jsonString.data(using: .utf8)
let base64Encoded = utf8str?.base64EncodedString(options: [])
return base64Encoded!
}

Accept more than one status code range with Alamofirie request

I would like to accept classic status code range (2XX) but also some extra error status code. So, how can i do this with the validate method of Alamofire Request?
Something like that:
Alamofire.request(self)
.validate(statusCode: [ 200..<300 , 403 ])
.responseJSON { response in
switch response.result {
case .Success(let JSON):
...
case .Failure(let error):
...
}
})
Alamofire accepts a Range<Int> parameter with acceptable codes. A range requires that all elements are consecutive, so you'll have to code your own validator. This should work:
.validate { _, response in
let acceptableStatusCodes: [Range<Int>] = [200..<300, 403...403]
if acceptableStatusCodes.map({$0.contains(response.statusCode)}).reduce(false, combine: {$0 || $1}) {
return .Success
} else {
let failureReason = "Response status code was unacceptable: \(response.statusCode)"
return .Failure(Error.errorWithCode(.StatusCodeValidationFailed, failureReason: failureReason))
}
}
You can also declare it in a Request extension for better code reusability:
extension Request {
func validateStatusCode() -> Request {
return self.validate { _, response in
let acceptableStatusCodes: [Range<Int>] = [200..<300, 403...403]
if acceptableStatusCodes.map({$0.contains(response.statusCode)}).reduce(false, combine: {$0 || $1}) {
return .Success
} else {
let failureReason = "Response status code was unacceptable: \(response.statusCode)"
return .Failure(Error.errorWithCode(.StatusCodeValidationFailed, failureReason: failureReason))
}
}
}
}
And call it like this:
Alamofire.request(self)
.validateStatusCode()
.responseJSON { response in
switch response.result {
case .Success(let JSON):
...
case .Failure(let error):
...
}
})

Swift Alamofire response status code

How can I get status code from the Alamofire response?
In the latest version I can use validate but I need to check what the status code is.
Code:
Alamofire.request(.GET, "http://example.com/url")
.responseJSON { response in
}
This works (after #MirzaDelic pointed out my mistake):
Alamofire.request(.get, "http://www.google.com")
.responseJSON { response in
if response.response.statusCode == 404 {
// do something
} else {
// do something else
}
}
In Alamofire 4.0 swift3 branch, I needed exactly:
Alamofire.request(request, withMethod: .get, parameters: parameters, encoding: .url, headers: nil)
.validate()
.responseJSON { response in
switch response.result {
case .success:
let statusCode = (response.response?.statusCode)!
print("...HTTP code: \(statusCode)")
}
}
While the above methods will work, there is a more efficient way to do this. response.response.statusCode returns a status code that could very in large amounts. Alamofire includes two functions that are useful for this case, isSuccess and isFailure.
Alamofire.request(.get, "http://example.com/url").responseJSON { response in
let responseErrorCode = response.response!.statusCode
if response.result.isSuccess {
print("Successful HTTP code: \(responseErrorCode)")
// Run code if request is successful
} else if response.result.isFailure {
print("Failure HTTP code: \(responseErrorCode)")
// Run code if request isn't successful
}
}
By using the code above you can easily know whether the HTTP code is good or bad.
With Alamofire 5.6, if you add .validate(statusCode: [200]) to your AF request you can then inspect the AFError of the result.
func request(_ requestConvertible: any URLRequestConvertible) async throws {
switch await AF
.request(requestConvertible, interceptor: interceptor)
.validate(statusCode: [200])
.serializingDecodable(Empty.self, emptyResponseCodes: [200])
.result {
case .failure(let error):
if error.responseCode == 401 {
// Handle 401 statusCode
}
throw error
case .success:
break
}
}
Or for a Decodable type (from a JSON response):
func requestDecodable<Value: Decodable>(_ requestConvertible: any URLRequestConvertible, to type: Value.Type) async throws -> Value {
let request = AF.request(requestConvertible, interceptor: interceptor)
.validate(statusCode: [200])
let response = request.serializingData(emptyResponseCodes: [200])
let result = await response.result
switch result {
case .failure(let error):
if request.response?.statusCode == 401 {
// Handle 401 statusCode
}
throw error
case .success(let data):
return try JSONDecoder().decode(type.self, from: data)
}
}