Alamofire multiple parameters (Query and Form) Swift 4 - swift

I'm having a problem sending a POST request with Alamofire.
I need to send the usser and password fields as application/x-www-form-urlencode and also some query data in the url.
I am creating a URLRequest to handle the process, but I'm getting always a 400 response from the server, so I guess the problem must be in the way I create the request.
This is the example in Postman:
I need to send a param in the url and two more in as application/x-www-form-urlencode
Postman 1 - Parameters
Postman 2 - ContentType
I need to do this (that i have in Android)
#FormUrlEncoded
#POST(Constants.AUTH_LDAP)
Call<ResponseBody> authLdap(
#Query(value = Constants.PARAM_REQ, encoded = true) String req,
#Field(Constants.PARAM_LOGIN) String login,
#Field(Constants.PARAM_PASSWORD) String password
);
And this is what I have in swift
let queryParamters = [Constants.Params.PARAM_REQ:req]
let headers = ["Content-Type": "application/x-www-form-urlencoded"]
let fieldParameters = [
Constants.Params.PARAM_LOGIN : user,
Constants.Params.PARAM_PASSWORD : pass]
let url = URL(string: Constants.EndPoints.AUTH_LDAP)
let request = URLRequest(url: url!)
let encoding = try URLEncoding.default.encode(request, with: queryParamters as Parameters)
let encodingpa = try URLEncoding.httpBody.encode(request, with: fieldParameters as Parameters)
var urlRequest = encodingpa
urlRequest.url = encoding.url
urlRequest.allHTTPHeaderFields = headers
Alamofire.request(urlRequest).responseData(completionHandler: { response in
switch response.result {
case .success:
print("sucess")
print(response.response)
case .failure(let error):
print(error)
}
})
Thanks for your help.

Try to create url from queryParameters using URLComponents like
var urlComponents = URLComponents(string: Constants.EndPoints.AUTH_LDAP)!
urlComponents.queryItems = [
URLQueryItem(name: Constants.Params.PARAM_REQ, value: req)
]
let headers = ["Content-Type": "application/x-www-form-urlencoded"]
var request = URLRequest(url: urlComponents.url!)
request.httpMethod = "POST"
request.httpBody = try? JSONSerialization.data(withJSONObject: fieldParameters)
request.allHTTPHeaderFields = headers
Alamofire.request(request).responseJSON { response in
}

Related

How to translate a python script to swift (http post request)?

I have a working python script that gets cookies from a site. I want to convert it to Swift script, but I do something wrong and can not understand where.
#!/usr/bin/env python
import warnings
import json
import os
import requests
auth_login='someName'
auth_password='somePassword'
passport_params = {'from': 'passport', 'retpath': 'https://192.168.0.1/passport?mode=passport', 'passwd': auth_password, 'login': auth_login, 'display': 'page'}
passport_session = requests.session()
passport_error_passwd = u"wrong pass"
passport_error_login = u"no such users"
print('Connecting to passport...')
try:
passport_request = passport_session.post('https://192.168.0.1/passport?mode=auth', data=passport_params, verify=False)
except:
print('Error connecting')
if os.name == 'nt':
os.system("pause")
exit(1)
else:
print('Authentication successful')
passport_cookies = requests.utils.dict_from_cookiejar(passport_session.cookies)
print('cookies=')
print(passport_cookies)
I am not sure that my post request works correctly, so my cookies are empty.
let auth_login = "someName"
let auth_password = "somePassword"
let url = URL(string: "https://192.168.0.1/passport?mode=auth")!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.httpMethod = "POST"
let parameters = [
"from": "passport",
"retpath": "https://192.168.0.1/passport?mode=passport",
"passwd": auth_password,
"login": auth_login,
"display": "page"
]
request.httpBody = try? JSONSerialization.data(withJSONObject: parameters)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard
// let data = data,
let response = response as? HTTPURLResponse,
let fields = response.allHeaderFields as? [String: String]
else {
print("error", error ?? URLError(.badServerResponse))
return
}
let cookies = HTTPCookie.cookies(withResponseHeaderFields: fields, for: url)
print("cookies:\n\(cookies)")
guard (200 ... 299) ~= response.statusCode else {
print("statusCode should be 2xx, but is \(response.statusCode)")
print("response = \(response)")
return
}
}
task.resume()
Your python code is sending these:
passport_params = {'from': 'passport', 'retpath': 'https://192.168.0.1/passport?mode=passport', 'passwd': auth_password, 'login': auth_login, 'display': 'page'}
as POST data payload.
While your Swift code
let parameters = [
"from": "passport",
"retpath": "https://192.168.0.1/passport?mode=passport",
"passwd": auth_password,
"login": auth_login,
"display": "page"
]
request.httpBody = try? JSONSerialization.data(withJSONObject: parameters)
is doing that as JSON http body.
So these requests are very different, hence the problem you encounter.
Have a look at this answer how to configure POST data in a request in Swift .

Passing headers to URL with Swift URLSession

I don't feel like sharing the actual link as it may have some private information so don't be surprised if it doesn't work.
I have a link that looks like this: www.somelink.com/stuff/searchmembers?member=John
And some headers that I need to pass, like Login: Admin, Password: Admin
When I use this site everything seems to be working just fine, I put the link, make it GET and put headers in key:value format and as a result I get the list of all members, but how can I do the same with URLSession? Here's what I currently have and I don't get anything at all. What am I doing wrong there?
func getAllMembers(urlString: String) {
guard let url = URL(string: urlString) else { return }
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("Admin", forHTTPHeaderField: "Login")
request.setValue("Admin", forHTTPHeaderField: "Password")
request.httpBody = "member=John".data(using: .utf8)!
URLSession.shared.dataTask(with: request) { (data, response, error) in
print(response)
print(data)
}.resume()
}
Here is What You're Doing Wrong:
Your member=John is actually a URL query parameter. In general, URL requests have query parameters as a part of the URL string itself and not the httpbody.
Quick and Dirty Solution:
You should be good to go if you remove
request.httpBody = "member=John".data(using: .utf8)!
and instead pass the whole "www.somelink.com/stuff/searchmembers?member=John" into your getAllMembers(urlString:) function.
A Better Solution:
Let's say John's username is j o h n. Your function wouldn't make it past that first guard because spaces aren't valid URL string characters.
I like to use URLComponents because it saves me the trouble of having to handle spaces and such.
Here's how I'd write your function:
func getJohnMember(urlString: String) {
//URLComponents to the rescue!
var urlBuilder = URLComponents(string: urlString)
urlBuilder?.queryItems = [
URLQueryItem(name: "member", value: "j o h n")
]
guard let url = urlBuilder?.url else { return }
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("Admin", forHTTPHeaderField: "Login")
request.setValue("Admin", forHTTPHeaderField: "Password")
URLSession.shared.dataTask(with: request) { (data, response, error) in
print(response)
print(String(data: data, encoding: .utf8)) //Try this too!
}.resume()
}
Just to be clear, I would pass just "www.somelink.com/stuff/searchmembers" into the first parameter.
Now if I were to print(url) after the guard let, I'd get
www.somelink.com/stuff/searchmembers?member=j%20o%20h%20n
Much easier this way, no?
That member=John is a URL-query parameter, not part of the request body. So you need to add it to the URL itself.
func getAllMembers(urlString: String) {
guard let url = URL(string: "\(urlString)?member=John") else { return }
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("Admin", forHTTPHeaderField: "Login")
request.setValue("Admin", forHTTPHeaderField: "Password")
URLSession.shared.dataTask(with: request) { (data, response, error) in
print(response)
print(data)
}.resume()
}

My swift HTTP POST request is not being processed properly by a PHP api

I am trying to get a post request to a PHP api. I need to be able to send the request in Json format. The PHP file collects the post request like so:
$postBody = $_POST ['request'];
$signature = $_POST ['signature'];
$rpcRequest = json_decode ( $postBody, true );
I need to build a request that is formatted so the api can read my information. I am building my request like so:
//Here I am building the request as a string. This string is used to get the signature.
var params =
"""
{"method":"phoneNumberVerificationStart","params":{"number":"\(PhoneNumber)"},"id":1}
"""
//here I build the request by using a dictionary.
var jsonParams = ["request": ["method": "phoneNumberVerificationStart","id": 1, "params": ["number": "\(PhoneNumber)"] ]] as NSMutableDictionary
let urlString = "******************************"
//below is just hashing the params into sha256
let hashedParams = sha256(request: params)
let signature = hashedParams.hexEncodedString()
//Take what was just hashed and put it into the signature variable
jsonParams["signature"] = signature
//jsonData takes my built dictionary and turns it into a json format to be sent.
let jsonData = try? JSONSerialization.data(withJSONObject: jsonParams, options: .prettyPrinted)
guard let requestURL = URL(string:urlString) else{return}
let session = URLSession.shared
// Set up the post request to send to the server.
let request = NSMutableURLRequest(url:requestURL)
request.httpMethod = "POST"
// Add the jsonData to the body of the http request. This data is json and when printed out in string form it looks like this:
// ( {"request":{"id":1,"method":"phoneNumberVerificationStart","params":{"number":"**********"}},"signature":"2ebdd87bdc66a04419bfd60e7c9b257039bf66dacd1623a1995c971e7cb68ed6"}
//For some odd reason Id shifts up to the front of the json file?
request.httpBody = jsonData
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
print(String(data: request.httpBody!, encoding: .utf8)!)
//After this I send the request the server does not understand my post request
let task = session.dataTask(with: request as URLRequest){
(data,respone, error) in
if error != nil {
print(error?.localizedDescription)
//print(String(data:myData!,encoding: .utf8)!)
}
do{
print (String(data: data!, encoding: .utf8)!)
}
I am thinking my problem is the request not being sent as a json object but rather raw data. I am receiving an error from the server that it cannot find the fields 'request' or 'signature'.

Swift REST Request PUT Optional(502 Bad Gateway: Registered endpoint failed to handle the request.)

I'm trying to do a PUT request using Swift. In a REST client, when I try to do a REST request the following way:
In Body- x-www-form-urlencoded, I add vote=1 and with id being taken in the param for example: /user/:id, it works!
I try to do the same in Swift code, it does not work and I get responseString = Optional(502 Bad Gateway: Registered endpoint failed to handle the request.
Here is my code:
var baseURL = "http://<domain>/user"
let putURL = baseURL + "/\(id)"
print(putURL)
let request = NSMutableURLRequest(URL: NSURL(string: putURL)!)
request.HTTPMethod = "PUT"
let putString = "vote=1"
request.HTTPBody = putString.dataUsingEncoding(NSUTF8StringEncoding)
request.timeoutInterval = 1500
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
guard error == nil && data != nil else {
print("error=\(error)")
return
}
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
}
task.resume()
You forgot to set the content type, e.g.
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
Without that, the server won't know what to do with the blob of random data that you just sent it.
I'm not saying that this is necessarily the only problem, but it is definitely a problem, and one big enough to cause the error you're seeing.

Converting CURL command for Locu to Swift

The Locu API provides this example using CURL to perform a location sensitive query:
curl -X POST https://api.locu.com/v2/venue/search -d '{
"api_key" : "f165c0e560d0700288c2f70cf6b26e0c2de0348f",
"fields" : [ "name", "location", "contact" ],
"venue_queries" : [
{
"location" : {
"geo" : {
"$in_lat_lng_radius" : [-37.7750, 122.4183, 5000]
}
}
}]
}'
This is my attempt in Swift:
let LOCU_API_KEY = "<API_KEY>"
let centerLatitude = mapView.region.center.latitude
let centerLongitude = mapView.region.center.longitude
let arr = [centerLatitude,centerLongitude,5000]
let url = NSURL(string: "https://api.locu.com/v2/venue/search")
var request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
var params = ["api_key":LOCU_API_KEY,"fields":["name","location","contact"], "venue_queries":[["location":["geo":["$in_lat_lng_radius":arr]]]]] as [String:AnyObject!]
var err: NSError?
NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: { (response:NSURLResponse!, data:NSData!, error:NSError!) -> Void in
if error == nil {
var err:NSError?
let httpResponse = response as NSHTTPURLResponse!
println(response.description)
if httpResponse.statusCode == 200 {
if var json = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error:&err) as? NSDictionary {
println(json)
}
}
}
})
I only get an HTTP 400 - Bad request for this and various simplifications, like just providing the api_key. Version 1_0 of the Locu works fine, although it doesn't have the features I need.
afRequestOperationManager.GET is performing a GET request rather than a POST request.
Furthermore, the request data must be in JSON, whereas you are using URL parameters.
As others have said you need to use .POST or in someway do a POST request not a GET.
Also, it looks like this line:
let urlString = "https://api.locu.com/v2/venue/"
Should be:
let urlString = "https://api.locu.com/v2/venue/search"
Right? Notice the "search" at the end. That is why you are getting 400 I assume (404 I guess?!).
Let us know if it worked.
The '-X POST part of the curl command means you need to do an HTTP POST, not an HTTP GET.
Try using afRequestOperationManager.POST instead.