How i can Load POST URLRequest with parameter in WKWebView? - ios

Sorry For this my English is weak
I try many types of a solution but not working in Xcode 11.2.1 and swift 5
I try this
var urlRequest = URLRequest(url: URL(string: "https://xxxxxx/login")!)
urlRequest.httpMethod = "POST"
let params = [
"username": SessionManager.shared.username!,
"password": SessionManager.shared.password!,
"vhost": "standard"
]
let postString = self.getPostString(params: params)
urlRequest.httpBody = postString.data(using: .utf8)
webView.load(urlRequest)
...
//helper method to build url form request
func getPostString(params:[String:String]) -> String
{
var data = [String]()
for(key, value) in params
{
data.append(key + "=\(value)")
}
return data.map { String($0) }.joined(separator: "&")
}
and this
Post Request with Parameter
And also try to add below lines in my code
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
But not Working
I fire the Request because not working the WKWebView screen is Open but not Load request.
If I not set navigationDelegate and open normal URL then it is working completely
If I set navigationDelegate then blank page come in all Request Like Normal URL fire or post parameter URL fire, All are coming to Blank Page in
I can't understand what is the Problem with WKWebView
Please help me.
Thanks in advance

The request body uses the same format as the query string:
parameter=value&also=another
Therefore the content type of your request is of type application/x-www-form-urlencoded :
let postString = self.getPostString(params: params)
urlRequest.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
urlRequest.httpMethod = "POST"
urlRequest.httpBody = postString.data(using: .utf8)
webView.load(urlRequest)

Try this, we will initiate a POST request using URLSession convert the data returned by the server to String and instead of loading the url we will use loadHTMLString which will:
Set the webpage contents and base URL.
and the content is our converted string::-
var request = URLRequest(url: URL(string: "http://www.yourWebsite")!)
request.httpMethod = "POST"
let params = "Your Parameters"
request.httpBody = params.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { (data : Data?, response : URLResponse?, error : Error?) in
if data != nil {
if let returnString = String(data: data!, encoding: .utf8) {
self.webView.loadHTMLString(returnString, baseURL: URL(string: "http://www.yourWebsite.com")!)
}
}
}
task.resume()

I think we not need to use URLSession.dataTask, simply create URLRequest and declare your method + with stating header fields like this:
private final func postRequestToURL(_ urlString: String) {
guard let url = URL(string: urlString) else {
debugPrint("Error: Invailed URL!")
return
}
var parameters = Parameters()
parameters["name"] = "Example"
parameters["surname"] = "ExmpleExample"
parameters["timeZone"] = "MiddleEast/MENA"
parameters["test"] = "YES"
var urlRequest = URLRequest(url: url)
urlRequest.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
urlRequest.setValue("application/json", forHTTPHeaderField: "Accept")
urlRequest.allowsCellularAccess = true
urlRequest.httpMethod = "POST"
let postString = parameters.getPostString()
urlRequest.httpBody = postString.data(using: .utf8)
if let wkNavigation = self.webView.load(urlRequest) {
debugPrint("Success: \(wkNavigation.description)")
} else {
debugPrint("Failure: Cannot load current request.")
}
}
Here we can convert our parameters to String by this extension:
public extension Dictionary where Key == String, Value == Any {
func getPostString() -> String {
var data = [String]()
for(key, value) in self {
data.append(key + "=\(value)")
}
return data.map { String($0) }.joined(separator: "&")
}
}
I am using this code over my commercial app.
Additional info: I allowed request eligible to run over cellular by marking allowsCellularAccess = true this is optional

Related

How to pass two or many values in WKWebView's HTTP request body?

I want to pass two values in HTTP request body. I try to do it like this but it isn't working. can anyone help me?
guard let url = URL(string: "*****") else { return }
let request = NSMutableURLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let post: String = "cardId=\(viewModel.getCardId())&requestId=\(viewModel.getRequestId())"
if let postData: Data = post.data(using: String.Encoding.ascii, allowLossyConversion: true) {
request.httpBody = postData
webView.load(request as URLRequest)
}

Swift function to return multiple types

I'm trying to build a utility function called makePostBuilder which looks something like this.
fileprivate func makePostRequest(apiUrl: String, params: [String: String]) -> URLRequest? {
// build url
let urlString = "\(apiUrl)"
guard let serviceUrl = URL(string: urlString) else { return nil }
// build url request
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
//set http body for url request with incoming params
guard let httpBody = try? JSONSerialization.data(withJSONObject: params, options: []) else {
return nil
}
request.httpBody = httpBody
return request
}
The return type of this function is obviously incorrect. I would like it to either return a URLRequest instance OR an Error instance. The error instance is mainly so the optional unwrapping can return a valuable message instead of just nil (as per the current implementation.
I was thinking along the lines of a typealias, but I am not sure if that is the right approach.
//not sure if this is right
typealias CustomRequestType = (URLRequest, Error)
At the end of the appropriate type definitions, I would like the function to look something like this
fileprivate func makePostRequest(apiUrl: String, params: [String:String]) -> CustomType {
let urlString = apiUrl
guard let serviceUrl = URL(string: urlString) else { return //error based on customtype? }
// build url request
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
//set http body for url request with incoming params
guard let httpBody = try? JSONSerialization.data(withJSONObject: params, options: []) else {
return //error type
}
//return success type
request.httpBody = httpBody
return request
}
I think I'm getting close, but not quite there yet. I'd also love if the community could point me to some docs!
UPDATE: Possible Solution?
//does this seem plausible?
enum DCError: String, Error {
case invalidUrl = "the url seems to be invalid"
}
typealias DCUrlRequestType = Result<URLRequest, Error>
fileprivate func makePostRequest(apiUrl: String, params: Dictionary<String, String>) -> DCUrlRequestType {
let urlString = apiUrl
guard let serviceUrl = URL(string: urlString) else {
return DCUrlRequestType.failure(DCError.invalidUrl)
}
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
return DCUrlRequestType.success(request)
}
There is a built-in enum Result you can use as your return type. And you can use URLError(code: .badURL) (provided by Foundation) in the case where you can't create the URL. Thus:
fileprivate func makePostRequest(apiUrl: String, params: [String: String]) -> Result<URLRequest, Error> {
let urlString = "\(apiUrl)"
guard let serviceUrl = URL(string: urlString) else {
return .failure(URLError(.badURL))
}
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
do {
request.httpBody = try JSONSerialization.data(withJSONObject: params, options: [])
} catch {
return .failure(error)
}
return .success(request)
}
BUT…
The natural way to write this function is to declare that it throws, like this:
fileprivate func makePostRequest(apiUrl: String, params: [String: String]) throws -> URLRequest? {
let urlString = "\(apiUrl)"
guard let serviceUrl = URL(string: urlString) else {
throw URLError(.badURL)
}
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONSerialization.data(withJSONObject: params, options: [])
return request
}
and then let the caller use do/catch if she wants to handle the error, instead of making the caller switch over the Result cases.
If the caller really wants a Result, she can use the Result(catching:) initializer, which (with trailing closure syntax) looks like this:
let requestResult = Result { try makePostRequest(apiUrl: urlString, params: [:]) }

How to add urlencoded parameter to httpBody in urlRequest

i have created one common class for alamofire request
i want to send parameters as aplication/x-www-form-urlencoded
how to add the parameters to my urlRequest
i have managed to add parameters as application/json to urlRequest using below code
do {
urlRequest.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: [])
} catch {
throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
}
i need something similar for aplication/x-www-form-urlencoded
here is my parameters
case .ewalletData :
return [K.APIParameterKey.token :"OP8JHOEOZ5KJW1X",K.APIParameterKey.fromMobile:"true",K.APIParameterKey.adminName:"binaryecom",K.APIParameterKey.limit:"100",K.APIParameterKey.offset:"0",K.APIParameterKey.userName:"OC6DGH"]
here is the code it works for me in swift 4:
let postString = "your parameter="+value+"&your parameter="+value
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request, completionHandler: completionHandle)
task.resume()
try this :
guard let request_url = URL(string: Url) else { return }
let parameterDictionary = ["your parameter" : value]
var request = URLRequest(url: request_url)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
request.setValue("aplication/x-www-form-urlencoded", forHTTPHeaderField: "String")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: []) else {
return
}
request.httpBody = httpBody

Receive POST request from Swift in Node.js

I am trying to receive and process a POST request being sent from my iOS app to my Node.js web server. The server responds with HTTP Error 502 whenever I try to send this POST request. Could you please look at my code below and see what is wrong with it? Thank you!
Node.js Code
app.post('/applogin', function(req, res) {
var parsedBody = JSON.parse(req.body);
console.log(parsedBody)
});
Swift Code (POST function)
func httpPost(jsonData: Data) {
if !jsonData.isEmpty {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = jsonData
URLSession.shared.getAllTasks { (openTasks: [URLSessionTask]) in
NSLog("open tasks: \(openTasks)")
}
let task = URLSession.shared.dataTask(with: request, completionHandler: { (responseData: Data?, response: URLResponse?, error: Error?) in
NSLog("\(response)")
})
task.resume()
}
}
Swift Code (sending of the POST request)
#IBAction func onClick(_ sender: Any) {
let username = Username.text
let password = Password.text
var dataString = "username: \(username), password: \(password)"
let data = dataString.data(using: .utf8)
httpPost(jsonData: data!)
}
Thanks in advance!
You have to send a json instead dataString, and you have to set the "Content Type" header with value "application/json"
Swift 2
let request = NSMutableURLRequest(URL: requestUrl)
request.HTTPMethod = "POST"
let params = ["username" : username, "password" : password] as Dictionary<String, AnyObject>
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options:NSJSONWritingOptions.PrettyPrinted)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
Many answers they don't mention that we need to set header for the request from Swift side before sending to the backend otherwise it'll be a string in a wrong format that we can't use JSON.parse, here's what I firgured out (NOTE the IMPORTANT line):
let json = [
"email": emailTextField.text
]
let jsonData = try! JSONSerialization.data(withJSONObject: json)
let url = URL(string: BASE_URL + "/auth/register")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
// insert json data to the request
request.httpBody = jsonData
//IMPORTANT
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON)
}
}
task.resume()
And in your NodeJS with Express just call req.body and you're done
Try this:
app.post('/applogin', function(req, res) {
var parsedBody = JSON.parse(req.body);
console.log(parsedBody)
res.send("Request received")
});

Alamofire put with array of ObjectMapper

I have array of ObjectMapper:
var arr = [Model]
now how can i use Alamofire to send this array to server with .PUT or .POST method?
Alamofire.request(.PUT, Config().apiGroup, parameters: arr, encoding: .JSON)
it says that parameters type is [String : AnyObject]?.
I tried with this too:
var params = Array<AnyObject>()
for entry in arr {
params.append(Mapper().toJSON(entry))
}
and then to pass params to parameters, but still getting error.
Any solution?
You can do this to convert:
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)
}

Resources