POST request using Alamofire.request and URLRequestConvertible - ios

Below is the code of my URLRequestConvertible
enum Router: URLRequestConvertible {
static let baseURLString = "http://example.com/"
case LoginRequest(String, String)
case SignUpRequest(String)
case ForgotPasswordRequest(String)
var URLRequest: NSMutableURLRequest {
let result: (path: String, method: Method, parameters: [String: AnyObject]) = {
switch self {
case .LoginRequest(let userName, let password):
let params = [userNameKey: userName, passwordKey: password]
return ("/AppUsers/login", .POST, params)
case .SignUpRequest(let profile):
let params = [fullNameKey: profile]
return ("/AppUsers/add", .POST, params)
case .ForgotPasswordRequest(let emailId):
let params = [userNameKey: emailId]
return ("/AppUsers/forgot_password", .POST, params)
}
}()
let URL = NSURL(string: Router.baseURLString)
let request = NSMutableURLRequest(URL: URL!.URLByAppendingPathComponent(result.path))
let encoding = ParameterEncoding.URL
request.URLRequest.HTTPMethod = result.method.rawValue
return encoding.encode(request, parameters: result.parameters).0
}
}
Now, I have below request which is working fine:
Alamofire.request(.POST, CommunicationService.Router.LoginRequest(txtUsername.text!, txtPassword.text!).URLRequest, parameters: ["email_id": txtUsername.text!, "password": txtPassword.text!], encoding: ParameterEncoding.JSON, headers: nil).responseJSON(options: NSJSONReadingOptions.MutableContainers) { (response) -> Void in
print(response)
}
But I want to make the use of URLRequestConvertible for Parameter passing for POST request. Let me know what is the best way for POST request using below API:
request(.POST, CommunicationService.Router.LoginRequest(txtUsername.text!, txtPassword.text!).URLRequest).responseJSON(completionHandler: { (response) -> Void in
print(response)
})
Actually, above code is giving Invalid response with below error message
FAILURE: Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}
What's wrong with the request generated using request(Method, URLStringConvertible) method?
Can any one help me?

You need to use the other form of the request method.
let loginRequest = CommunicationService.Router.LoginRequest(username, password).URLRequest
Alamofire.request(loginRequest).responseJSON { in
print(response)
}
Otherwise you are only using the URLString from the original NSURLRequest being created by the Router.

Related

Replicating post method in Postman with parameters and body-raw into Alamofire

I'm having a problem on using Alamofire. When I try to post a request using a generic parameters like ["name":"John", "age":"27"] it always succeeds. But, when I try to use a web service that requires parameters and a body-raw for a base64 string I'm not able to get a successful response from the server. Though it succeeds when I use Postman. Does anyone knows how to do this on Alamofire 4? Here is the screenshot of my postman.
Thank you!
#nathan- this is the code that I used. I just assumed that the base64String inside the "let paramsDict" has a key value named "data" though it doesn't have a key name in postman.
let urlString = ApiManager.sharedInstance.formsURL + ApiManager.sharedInstance.mobileFormsImageUpload
let paramsDict = ["token": token, "fileID":"2", "filename":"images.png", "data": base64String] as [String : Any]
Alamofire.request(urlString, method: .post, parameters: paramsDict, encoding: URLEncoding.httpBody, headers: [:])
.responseJSON{ response in
switch response.result {
case .success(let data):
debugPrint("SUCCESS")
case .failure(let error):
debugPrint("Request Error")
}
}
I already figured it out. It needs a custom encoding to make it work. All the parameters must be inlined with the url so the base64 string inside the parameter is the only to be encoded. Here is the code that I used.
struct CustomPostEncoding: ParameterEncoding {
func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var request = try URLEncoding().encode(urlRequest, with: parameters)
let base64 = parameters?["data"] as! String
let finalBase64Format = "\"" + base64 + "\""
let postData = NSData(data: finalBase64Format.data(using: String.Encoding.utf8)!)
request.httpBody = postData as Data
return request
}
}
func uploadImageBase64(){
let jpegCompressionQuality: CGFloat = 0.9 // Set this to whatever suits your purpose
if let base64String = UIImageJPEGRepresentation(testIMG, jpegCompressionQuality)?.base64EncodedString() {
var token = String()
if let data = UserDefaults.standard.data(forKey: "userProfile"),
let user = NSKeyedUnarchiver.unarchiveObject(with: data) as? UserProfile{
token = user.token
} else {
print("There is an issue")
}
let headers = [
"content-Type": "application/json"
]
let urlString = "http://localhost/FormsService.svc/Getbase64?filename=test.png&fileID=1151&token=80977580xxx"
let paramsDict = ["data": base64String] as [String : Any]
Alamofire.request(urlString, method: .post, parameters: paramsDict, encoding: CustomPostEncoding(), headers: headers)
.responseJSON{ response in
print("response JSON \(response.result)")
}
.response{ response in
print("RESPONSE \(response)")
}
}
}

Alamofire add body as String in iOS APP

So here is the thing, Im trying to use Almofire to post header and a body (as string) to an API.
_ = Alamofire.request("http://myurl", method: .post, parameters: param, encoding: JSONEncoding.default, headers: ["Authorization" : token])
.responseJSON { response in
switch response.result {
case .success(let data):
let json = JSON(data)
print(json)
case .failure( let error):
_ = SweetAlert().showAlert("Data Error!", subTitle: "Something Is Wrong!! Please contact Support", style: AlertStyle.warning)
}}
this works fine..
However I cant figure out how to pass a body string (this is the ID i pass to get data) API does not accept any parametrs (as key value or json) unless if it is just a String (ID). any help would be greatly appreciated.
Add custom parameter like below
var customParameters = [String : String]()
customParameters["key1"] = "Value1"
customParameters["key2"] = "Value2"
_ = Alamofire.request("http://myurl", method: .post, parameters: customParameters, encoding: JSONEncoding.default, headers: ["Authorization" : token])
.responseJSON { response in
switch response.result {
case .success(let data):
let json = JSON(data)
print(json)
case .failure( let error):
_ = SweetAlert().showAlert("Data Error!", subTitle: "Something Is Wrong!! Please contact Support", style: AlertStyle.warning)
}}
I found the answer from https://stackoverflow.com/a/42513496/8099966. this imethod can sed a String value on body. So changed my code like this ..
struct JSONStringArrayEncoding: ParameterEncoding {
private let myString: String
init(string: String) {
self.myString = string
}
func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var urlRequest = urlRequest.urlRequest
let data = myString.data(using: .utf8)!
if urlRequest?.value(forHTTPHeaderField: "Content-Type") == nil {
urlRequest?.setValue("application/json", forHTTPHeaderField: "Content-Type")
}
urlRequest?.httpBody = data
return urlRequest!
}}
then call the API like this...
_ = Alamofire.request("http://myurl.com", method: .post, parameters: param, encoding: JSONStringArrayEncoding.init(string: "my String id to send"), headers: ["Authorization" : token])

Alamofire 4.3 with Swift 3 , POST request does not working with URL Parameters

I am trying to send a post request as follows, My Router as follows
enum ProfieRouter: URLRequestConvertible {
case loginUser(parameters: Parameters)
case resetPassword(parametrs: Parameters)
var method: HTTPMethod {
switch self {
case .loginUser:
return .post
case .resetPassword:
return .post
}
}
var path: String {
switch self {
case .loginUser:
return "app/api.php?request=login"
case .resetPassword:
return "app/api.php?request=forgettenPassword"
}
}
func asURLRequest() throws -> URLRequest {
let BASEURL = "https://www.example.com/"
let url = try BASEURL.asURL()
var urlRequest = URLRequest(url: url.appendingPathComponent(path))
urlRequest.httpMethod = method.rawValue
switch self {
case .loginUser(let parameters):
urlRequest = try URLEncoding.default.encode(urlRequest, with: parameters)
case .resetPassword(let parameters):
urlRequest = try URLEncoding.default.encode(urlRequest, with: parameters)
}
return urlRequest
}
}
This is how i call it from ViewController,
#IBAction func signInButtonClicked(_ sender: Any) {
let parameters: Parameters = [
"email": "xxxxxx",
"password": "xxxxxx"
]
Alamofire.request(ProfieRouter.loginUser(parameters: parameters)).responseJSON{ response in
switch response.result {
case .success:
print(response)
break
case .failure(let error):
print(error)
}
}
}
But i got following error as follows,
responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}))
Please note that, my API response is a valid when i checked with POSTMAN and Advanced REst Client. And i have tried several question regarding following error but non of them work in my case.
Please can someone point out the mistake i have done here.
Thank you.
Try this..
Modify you web-service calling code like this :
// Add default headers if needed.(As per your web-service requirement)
let headers: HTTPHeaders = [
"Accept": "text/html",
"Content-Type" : "application/x-www-form-urlencoded"
]
Alamofire.request("Your URL", method: .post, parameters: parameters, encoding: URLEncoding.httpBody, headers: headers).validate().responseJSON { (response) in
debugPrint(response)
}
Hope it helps.

How to get response headers when using Alamofire in Swift?

I'm using Alamofire for my Rest (POST) request and getting JSON response seamlessly. But i can access only response body. I want to get response headers. Isn't it possible when using Alamofire?
Here is my code snippet:
#IBAction func loginButtonPressed(sender: UIButton) {
let baseUrl = Globals.ApiConstants.baseUrl
let endPoint = Globals.ApiConstants.EndPoints.authorize
let parameters = [
"apikey": "api_key_is_here",
"apipass": "api_pass_is_here",
"agent": "agent_is_here"
]
Alamofire.request(.POST, baseUrl + endPoint, parameters: parameters).responseJSON {
(request, response, data, error) in let json = JSON(data!)
if let result = json["result"].bool {
self.lblResult.text = "result: \(result)"
}
}
}
As response is of NSHTTPURLResponse type, you should be able to get the headers as followed:
response.allHeaderFields
Here is how to access the response headers in Swift 3:
Alamofire.request(.GET, requestUrl, parameters:parameters, headers: headers)
.responseJSON { response in
if let headers = response.response?.allHeaderFields as? [String: String]{
let header = headers["token"]
// ...
}
}
This code gets response header in Swift 4.2
Alamofire.request(pageUrlStr, method: .post, parameters: Parameter, encoding: URLEncoding.httpBody, headers: nil).responseJSON
{ response in
//to get JSON return value
if let ALLheader = response.response?.allHeaderFields {
if let header = ALLheader as? [String : Any] {
if let cookies = header["Set-Cookie"] as? String {
UserDefaults.standard.set(cookies, forKey: "Cookie")
}
}
}
}

POST request with a simple string in body with Alamofire

how is it possible to send a POST request with a simple string in the HTTP body with Alamofire in my iOS app?
As default Alamofire needs parameters for a request:
Alamofire.request(.POST, "http://mywebsite.example/post-request", parameters: ["foo": "bar"])
These parameters contain key-value-pairs. But I don't want to send a request with a key-value string in the HTTP body.
I mean something like this:
Alamofire.request(.POST, "http://mywebsite.example/post-request", body: "myBodyString")
Your example Alamofire.request(.POST, "http://mywebsite.example/post-request", parameters: ["foo": "bar"]) already contains "foo=bar" string as its body.
But if you really want string with custom format. You can do this:
Alamofire.request(.POST, "http://mywebsite.example/post-request", parameters: [:], encoding: .Custom({
(convertible, params) in
var mutableRequest = convertible.URLRequest.copy() as NSMutableURLRequest
mutableRequest.HTTPBody = "myBodyString".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
return (mutableRequest, nil)
}))
Note: parameters should not be nil
UPDATE (Alamofire 4.0, Swift 3.0):
In Alamofire 4.0 API has changed. So for custom encoding we need value/object which conforms to ParameterEncoding protocol.
extension String: ParameterEncoding {
public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var request = try urlRequest.asURLRequest()
request.httpBody = data(using: .utf8, allowLossyConversion: false)
return request
}
}
Alamofire.request("http://mywebsite.example/post-request", method: .post, parameters: [:], encoding: "myBody", headers: [:])
You can do this:
I created a separated request Alamofire object.
Convert string to Data
Put in httpBody the data
var request = URLRequest(url: URL(string: url)!)
request.httpMethod = HTTPMethod.post.rawValue
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let pjson = attendences.toJSONString(prettyPrint: false)
let data = (pjson?.data(using: .utf8))! as Data
request.httpBody = data
Alamofire.request(request).responseJSON { (response) in
print(response)
}
If you use Alamofire, it is enough to set encoding type to URLEncoding.httpBody
With that, you can send your data as a string in the httpbody although you defined it as json in your code.
It worked for me..
Updated for Badr Filali's question:
var url = "http://..."
let _headers : HTTPHeaders = ["Content-Type":"application/x-www-form-urlencoded"]
let params : Parameters = ["grant_type":"password","username":"mail","password":"pass"]
let url = NSURL(string:"url" as String)
request(url, method: .post, parameters: params, encoding: URLEncoding.httpBody, headers: _headers).responseJSON(
completionHandler: { response in response
let jsonResponse = response.result.value as! NSDictionary
if jsonResponse["access_token"] != nil
{
access_token = String(describing: jsonResponse["accesstoken"]!)
}
})
I modified #Silmaril's answer to extend Alamofire's Manager.
This solution uses EVReflection to serialize an object directly:
//Extend Alamofire so it can do POSTs with a JSON body from passed object
extension Alamofire.Manager {
public class func request(
method: Alamofire.Method,
_ URLString: URLStringConvertible,
bodyObject: EVObject)
-> Request
{
return Manager.sharedInstance.request(
method,
URLString,
parameters: [:],
encoding: .Custom({ (convertible, params) in
let mutableRequest = convertible.URLRequest.copy() as! NSMutableURLRequest
mutableRequest.HTTPBody = bodyObject.toJsonString().dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
return (mutableRequest, nil)
})
)
}
}
Then you can use it like this:
Alamofire.Manager.request(.POST, endpointUrlString, bodyObject: myObjectToPost)
Based on Illya Krit's answer
Details
Xcode Version 10.2.1 (10E1001)
Swift 5
Alamofire 4.8.2
Solution
import Alamofire
struct BodyStringEncoding: ParameterEncoding {
private let body: String
init(body: String) { self.body = body }
func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
guard var urlRequest = urlRequest.urlRequest else { throw Errors.emptyURLRequest }
guard let data = body.data(using: .utf8) else { throw Errors.encodingProblem }
urlRequest.httpBody = data
return urlRequest
}
}
extension BodyStringEncoding {
enum Errors: Error {
case emptyURLRequest
case encodingProblem
}
}
extension BodyStringEncoding.Errors: LocalizedError {
var errorDescription: String? {
switch self {
case .emptyURLRequest: return "Empty url request"
case .encodingProblem: return "Encoding problem"
}
}
}
Usage
Alamofire.request(url, method: .post, parameters: nil, encoding: BodyStringEncoding(body: text), headers: headers).responseJSON { response in
print(response)
}
If you want to post string as raw body in request
return Alamofire.request(.POST, "http://mywebsite.com/post-request" , parameters: [:], encoding: .Custom({
(convertible, params) in
let mutableRequest = convertible.URLRequest.copy() as! NSMutableURLRequest
let data = ("myBodyString" as NSString).dataUsingEncoding(NSUTF8StringEncoding)
mutableRequest.HTTPBody = data
return (mutableRequest, nil)
}))
I have done it for array from strings. This solution is adjusted for string in body.
The "native" way from Alamofire 4:
struct JSONStringArrayEncoding: ParameterEncoding {
private let myString: String
init(string: String) {
self.myString = string
}
func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var urlRequest = urlRequest.urlRequest
let data = myString.data(using: .utf8)!
if urlRequest?.value(forHTTPHeaderField: "Content-Type") == nil {
urlRequest?.setValue("application/json", forHTTPHeaderField: "Content-Type")
}
urlRequest?.httpBody = data
return urlRequest!
}
}
And then make your request with:
Alamofire.request("your url string", method: .post, parameters: [:], encoding: JSONStringArrayEncoding.init(string: "My string for body"), headers: [:])
I've used answer of #afrodev as reference. In my case I take parameter to my function as string that have to be posted in request. So, here is the code:
func defineOriginalLanguage(ofText: String) {
let text = ofText
let stringURL = basicURL + "identify?version=2018-05-01"
let url = URL(string: stringURL)
var request = URLRequest(url: url!)
request.httpMethod = HTTPMethod.post.rawValue
request.setValue("text/plain", forHTTPHeaderField: "Content-Type")
request.httpBody = text.data(using: .utf8)
Alamofire.request(request)
.responseJSON { response in
print(response)
}
}
func paramsFromJSON(json: String) -> [String : AnyObject]?
{
let objectData: NSData = (json.dataUsingEncoding(NSUTF8StringEncoding))!
var jsonDict: [ String : AnyObject]!
do {
jsonDict = try NSJSONSerialization.JSONObjectWithData(objectData, options: .MutableContainers) as! [ String : AnyObject]
return jsonDict
} catch {
print("JSON serialization failed: \(error)")
return nil
}
}
let json = Mapper().toJSONString(loginJSON, prettyPrint: false)
Alamofire.request(.POST, url + "/login", parameters: paramsFromJSON(json!), encoding: .JSON)
My case, posting alamofire with content-type: "Content-Type":"application/x-www-form-urlencoded", I had to change encoding of alampfire post request
from : JSONENCODING.DEFAULT
to: URLEncoding.httpBody
here:
let url = ServicesURls.register_token()
let body = [
"UserName": "Minus28",
"grant_type": "password",
"Password": "1a29fcd1-2adb-4eaa-9abf-b86607f87085",
"DeviceNumber": "e9c156d2ab5421e5",
"AppNotificationKey": "test-test-test",
"RegistrationEmail": email,
"RegistrationPassword": password,
"RegistrationType": 2
] as [String : Any]
Alamofire.request(url, method: .post, parameters: body, encoding: URLEncoding.httpBody , headers: setUpHeaders()).log().responseJSON { (response) in
let parameters = ["foo": "bar"]
// All three of these calls are equivalent
AF.request("https://httpbin.org/post", method: .post, parameters: parameters)
AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: URLEncodedFormParameterEncoder.default)
AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: URLEncodedFormParameterEncoder(destination: .httpBody))
Xcode 8.X , Swift 3.X
Easy Use;
let params:NSMutableDictionary? = ["foo": "bar"];
let ulr = NSURL(string:"http://mywebsite.com/post-request" as String)
let request = NSMutableURLRequest(url: ulr! as URL)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let data = try! JSONSerialization.data(withJSONObject: params!, options: JSONSerialization.WritingOptions.prettyPrinted)
let json = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
if let json = json {
print(json)
}
request.httpBody = json!.data(using: String.Encoding.utf8.rawValue);
Alamofire.request(request as! URLRequestConvertible)
.responseJSON { response in
// do whatever you want here
print(response.request)
print(response.response)
print(response.data)
print(response.result)
}

Resources