POST request with a simple string in body with Alamofire - ios

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)
}

Related

Convert httpBody for x-www-urlencoded

I'm doing a POST call to server but Alamofire always send the body as a JSON and not as a Form URL Encoded, I do know that in oder to encode the body I have to insert data(using: .utf8, allowLossyConversion: false), but I don't know where.
How can I fix my code?
This is my actual code:
func asURLRequest() throws -> URLRequest {
let url = try DBank.StagingServer.baseUrl.asURL()
var urlRequest = URLRequest(url: url.appendingPathComponent(path))
// HTTP Method
urlRequest.httpMethod = method.rawValue
// Common Headers
headers.forEach { (field, value) in
urlRequest.setValue(value, forHTTPHeaderField: field)
}
// Parameters
if let parameters = parameters {
do {
urlRequest.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: [])
} catch {
throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
}
}
I'm guessing you have response handler like below:
Alamofire.request(url, method: .post, parameters: params, encoding: URLEncoding(destination: .queryString), headers: headers)
.validate(statusCode: 200..<300)
.responseString { response in
//response.result.value will contain http response from your post call
}
With the result from this response you would set:
UserDefaults.standard.set("<result>", forKey: "<token>")

JSON data not parsing using with Alamofire in swift3

I have to parse json using alamofire
before am using json session its working fine getting data from the json. now am try to parse json using alamofire.
this is the code parse the json using json, this code working fine
func auth(_ email:String,password:String) {
var request = URLRequest(url:AppConstants.apiURLWithPathComponents("usersignin"))
let session = URLSession.shared
request.httpMethod = "POST"
let bodyData = "email=\(email)&passCode=\(password)&deviceType=iOS&deviceId=\(deviceToken)"
request.httpBody = bodyData.data(using: String.Encoding.utf8);
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
do {
if data != nil {
if let jsonData = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary {
errorCode = String(describing: jsonData["errorCode"]!)
msg = jsonData["msg"] as! String
print(errorCode)
print(jsonData)
if(errorCode == "1"){
DispatchQueue.main.async(execute: {
self.activityIndicator.stopAnimating()
})
} else {
self.name = jsonData.value(forKey: "name") as! String
if let kidsURLDetails = jsonData["kidsURLDetails"] as? NSArray {
for i in 0 ..< kidsURLDetails.count {
if kidsURLDetails[i] is NSDictionary {
let url = kidsURLDetails[i] as? NSDictionary
self.urls.append((url?["url"]) as! String)
}
}
}
self.serverURL = self.urls.joined(separator: ",")
print("ServerURL \(self.serverURL)")
let prefs:UserDefaults = UserDefaults.standard
prefs.setValue(self.name, forKey: "NAME")
DispatchQueue.main.async(execute: {
UIApplication.shared.endIgnoringInteractionEvents()
let controllerId = "NavID"
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let initViewController: UIViewController = storyboard.instantiateViewController(withIdentifier: controllerId) as UIViewController
self.present(initViewController, animated: true, completion: nil)
})
}
}
} else {
}
} catch let err as NSError {
print("JSON Error \(err)")
}
})
task.resume()
}
in above code I used post method with passing parameters, when I am trying post method with parameter passing in almofire am getting error "Extra argument 'method' in call", username and password coming from textfield so after enter the email and password I have pass the parameters using post method.
this is the code I will implemented in to alamofire json parse
var request = URLRequest(url:AppConstants.apiURLWithPathComponents("usersignin"))
let bodyData = "email=\(username)&passCode=\(passcode)&deviceType=iOS&deviceId=123456"
let deviceId = "1234"
let params: [String: Any] = ["email": username, "passCode": passwordstring, "deviceType": "IOS","deviceId":deviceId]
Alamofire.request(request, method: .post, parameters: params, encoding: JSONEncoding.default, headers: nil)
.responseJSON { response in
print(response.result.value as Any) }
if I can try this code working
Alamofire.request("http://www.kids.com/rk/api/usersignin?email=demo#kidsapp.com&passCode=123456&deviceType=&deviceId=", method: .post, parameters: nil, encoding: JSONEncoding.default, headers: nil)
.responseJSON { response in
print(response.result.value as Any) }
how can I parse the json post method passing parameters using alamofire. where I did mistake pls help me
You are passing wrong type in 1 param in call it should be URLConvertible(string or URL) not URLRequest. try below code.
let params: [String: Any] = ["email": username, "passCode": passwordstring, "deviceType": "IOS","deviceId":deviceId]
let url = URL(string: "http://www.kids.com/rk/api/usersignin")!
Alamofire.request(url, method: .post, parameters: params, encoding: JSONEncoding.default, headers: nil)
.responseJSON { response in
}
____________Edit___________
here header is post request headers(if any) or nil
let params: [String: Any] = ["email": username, "passCode": passwordstring, "deviceType": "IOS","deviceId":deviceId]
let urlString = "http://www.kids.com/rk/api/usersignin"
guard let url = URL(string: urlString), var request = try? URLRequest(url: url, method: .post, headers: header) else{
//
return
}
request.httpBody = params.map{ "\($0)=\($1)" }.joined(separator: "&").data(using: .utf8)
Alamofire.request(request).responseJSON { response in
}
If you need to send the parameters in url with post request you should use URLEncoding.default encoding rather than JSONEncoding.default. JSONEncoding is used when you need to send JSON data as body with content type application/json.
Change your code like:
Alamofire.request(url, method: .post, parameters: params, encoding: URLEncoding.default, headers: nil).responseJSON { response in
print(response.result.value as Any)
}
Or you can remove encoding parameter as URLEncoding is the default encoding of Alamofire.
// URL
let urlString = “URL_Here”
var params = [String: Any]()
//Contruct your params
params = ["email": username, "passCode": passwordstring, "deviceType": "IOS","deviceId":deviceId]
// Request
Alamofire.request(urlString, method: .post, parameters: params, encoding: JSONEncoding.default, headers: nil)
.validate(statusCode: 200..<300)
.responseJSON { response in
if (response.result.error == nil) {
let value = response.result.value
print(value)
}
else {
let errorString = response.result.error
print(errorString)
}
}

How to set UTF8 encoding for Alamofire POST request body?

I want to send UTF8 encoded JSON body to my REST API. My code right now is
var body : [String:Any]? = ["version":Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""];
.
.
body?["type"] = type
var url : String = UserDefaults.standard.value(forKey:"url") as! String
url.append("MobileLogin")
Alamofire.request(url, method: .post, parameters:body, encoding: JSONEncoding.default, headers: nil).responseJSON { (responseData) in
if((responseData.result.value) != nil) {
.
.
}
}
The problem is that the JSON sent in not UTF8 encoded. Any idea of how to set something like "JSONEncoding.encode("UTF8")" in the Alamofire request?
try this
let options = NSJSONWritingOptions()
let data = try NSJSONSerialization.dataWithJSONObject(parameters!, options: options)
mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
mutableURLRequest.HTTPBody = data
or other way
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(url, method: .post, parameters: [:], encoding: "myBody", headers: [:])

Alamofire 4 Swift 3 ParameterEncoding Custom

I updated my project to Swift 3 and Alamofire 4. I was using custom Encoding, but it's changed to other encoding methods. I am not able to find the alternative/equivalent to this:
alamoFire.request(urlString, method: HTTPMethod.post, parameters: [:], encoding: .Custom({
(convertible, params) in
let mutableRequest = convertible.URLRequest.copy() as! NSMutableURLRequest
let data = (body as NSString).data(using: String.Encoding.utf8)
mutableRequest.httpBody = data
return (mutableRequest, nil)
}), headers: headers()).responseJSON { (responseObject) -> Void in
switch responseObject.result {
case .success(let JSON):
success(responseObject: JSON)
case .failure(let error):
failure(error: responseObject)
}
}
I also tried by making URLRequest object and simple request its also giving me errors
var request = URLRequest(url: URL(string: urlString)!)
let data = (body as NSString).data(using: String.Encoding.utf8.rawValue)
request.httpBody = data
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers()
alamoFire.request(request).responseJSON { (responseObject) -> Void in
switch responseObject.result {
case .success(let JSON):
success(JSON)
case .failure(let error):
failure(responseObject, error)
}
}
Do point me in some direction, how to attach httpbody with the Alamofire 4
Try this method?
Alamofire.request(url, method: HTTPMethod.post, parameters: parameters, encoding: URLEncoding.httpBody, headers: nil).responseObject(completionHandler: { (response : DataResponse<T>) in
})
In Alamofire 4.0 you should use ParameterEncoding protocol. Here is an example, which makes any String UTF8 encodable.
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.com/post-request", method: .post, parameters: [:], encoding: "myBody", headers: [:])

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")
}
}
}
}

Resources