How to pass two parameter into webservice - swift

I have web service
http://dev.nsol.sg/projects/sneakers/Api/get_single_news
Method: POST
Required Parameters:
userid
newsid
Response:
success = 0 (error), 1 (success)
message = Description of result if success = 0 then message will have the detail description
data: if success = 1 then we will have complete details of common requirements like single news
newsurl: News Image URL + Concatenate Value of img from DB
Here is my try to fetch data from url
func single_news(userid: Int) {
var request = URLRequest(url: URL(string: news_url)!)
request.httpMethod = "POST"
//Pass your parameter here
let postString = "userid=\(userid)"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("error=(error)")
return
}
let json: Any?
do
{
json = try JSONSerialization.jsonObject(with: data, options: [])
print("abcnews")
//here is your JSON
print(json)
}
catch
{
return
}
guard let server_response = json as? NSDictionary else
{
return
}
}
task.resume()
}
How to pass the second parameter newsid.You can download the project from this link https://drive.google.com/file/d/1mBlYcNaW8K3s6Y2V6BY6zdM0Znvyw3Si/view?usp=sharing

Rewrite your function
func single_news(userid: Int , newsid : Int) {}
I assume that newsid is also an Int value.
And write your postString like this...
let postString = "userid=\(userid)&newsid=\(newsid)"
I hope this will help you.

If I understood correctly, you just want to create and send a JSON object with two properties.
You can do it like this:
let body: [String: Any] = ["userid": userid,
"newsid": newsid]
request.httpBody = try! JSONSerialization.data(withJSONObject: body, options: [])

Related

Swift 'Required String parameter 'grant_type' is not present' error when trying to get an access token

So I'm trying to make an app in Swift for which I need to login to the OAuth to retrieve an access token. The API takes the parameters 'grant_type' and 'code'.
I've tried:
let params = ["grant_type":"authorization_code", "code":"123456789"] as Dictionary<String, String>
var request = URLRequest(url: URL(string: "https://myschool.zportal.nl/api/v3/oauth/token")!)
request.httpMethod = "POST"
request.httpBody = try? JSONSerialization.data(withJSONObject: params, options: [])
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let session = URLSession.shared
let task = session.dataTask(with: request, completionHandler: { data, response, error -> Void in
do {
let json = try JSONSerialization.jsonObject(with: data!) as! Dictionary<String, AnyObject>
print(json)
} catch {
print("error")
}
})
task.resume()
This returns:
["response": {
data = (
);
details = "class org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'grant_type' is not present";
endRow = 0;
eventId = 216795;
message = "Internal problems.";
startRow = 0;
status = 500;
totalRows = 0;
}]
This is weird, because I did parse the 'grant_type' parameter, and as the correct value.
It should return something like:
{
"response": {
"status":200,
"message":"",
"startRow":0,
"endRow":27,
"totalRows":27,
"data":[
{
},
...
]
}
}
The standard message format requires a Form URL Encoded body, not a JSON one. Maybe adapt your code as in this Swift article.
Got it working:
#IBAction func sendButtonPressed(_ sender: UIButton) {
let urlString = "https://myschool.zportal.nl/api/v3/oauth/token"
performRequest(urlString: urlString)
}
func performRequest(urlString: String) {
if let url = URL(string: urlString) {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = "grant_type=authorization_code&code=1234567890".data(using: .utf8)
let session = URLSession(configuration: .default)
let task = session.dataTask(with: request, completionHandler: { data, response, error -> Void in
//print(response!)
do {
let json = try JSONSerialization.jsonObject(with: data!) as! Dictionary<String, AnyObject>
print(json)
} catch {
print("error")
}
})
task.resume()
}
}
Not the nicest code but I'll polish it later.
At first I parsed JSON but it turned out I needed to parse a String and turn it into a Data type using: .data(using: .utf8)

I am doing a post request where I want to type in a question and with the post request get the most common answer

I have done my Post-request but I am unsure about how to make it possible to send a full question and to get the most common answers back to my app.
I am in such a big need of this code in my program so would love to get some examples on how to make it work
Have tried to right the question into the parameters with a "+" instead of space which resulted into nothing.
#IBAction func GetAnswer(_ sender: Any) {
let myUrl = URL(string: "http://www.google.com/search?q=");
var request = URLRequest(url:myUrl!)
request.httpMethod = "POST"
let postString = questionAsked;
request.httpBody = postString.data(using: String.Encoding.utf8);
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if error != nil
{
print("error=\(String(describing: error))")
return
}
print("response = \(String(describing: response))")
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
let answer = parseJSON[" Answer "] as? String
self.AnswerView.text = ("Anwer: \(String(describing: answer))")
}
} catch {
print(error)
}
}
task.resume()
}
You do not use google.com/search, please check the api documentation
Paste following in Playground, should give a good start
struct Constants {
static let apiKey = "YOUR_API_KEY"
static let bundleId = "YOUR_IOS_APP_BUNDLE_ID"
static let searchEngineId = "YOUR_SEARCH_ENGINE_ID"
}
func googleSearch(term: String, callback:#escaping ([(title: String, url: String)]?) -> Void) {
let urlString = String(format: "https://www.googleapis.com/customsearch/v1?q=%#&cx=%#&key=%#", term, Constants.searchEngineId, Constants.apiKey)
let encodedUrl = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
guard let url = URL(string: encodedUrl ?? urlString) else {
print("invalid url \(urlString)")
return
}
let request = NSMutableURLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10)
request.httpMethod = "GET"
request.setValue(Constants.bundleId, forHTTPHeaderField: "X-Ios-Bundle-Identifier")
let session = URLSession.shared
let datatask = session.dataTask(with: request as URLRequest) { (data, response, error) in
guard
error == nil,
let data = data,
let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String : Any]
else {
// error handing here
callback(nil)
return
}
guard let items = json["items"] as? [[String : Any]], items.count > 0 else {
print("no results")
return
}
callback(items.map { ($0["title"] as! String, $0["formattedUrl"] as! String) })
}
datatask.resume()
}
Usage
googleSearch(term: "George Bush") { results in
print(results ?? [])
}
Create a new search engine using following url
https://cse.google.com/cse/create/new
If you would like search entire web, use following steps
edit your engine using https://cse.google.com/cse/setup/basic?cx=SEARCH_ENGINE_ID
remove any pages listed under Sites to search
turn on Search the entire web

Get request return error code 405 - method not allowed

I've wrote a function for GET request from rest and it says that i have method not allowed - code 405 which is werid and i can not find solution for that.
I am doing GET via current token which was assigned to the user after logged in.
Could someone have a look on the code and tell me what might be wrong ?
func getRequest() -> Void {
let json: [String: Any] = ["token": SessionMenager.Instance.token]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
// create post request
let url = URL(string: MY_URL)!
var request = URLRequest(url: url)
request.httpMethod = "GET"
// insert json data to the request
request.httpBody = jsonData
request.setValue("application/json;charest=utf-8", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
if let httpResponse = response as? HTTPURLResponse {
print("GET : code - \(httpResponse.statusCode)")
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON)
} else{
print(error.debugDescription)
}
}
task.resume()
}
Thanks in advance!!

swift URLRequest doesn't send parameters

In the code below
let bodyData = "?sub=\(id)&name=User&email=test#test.com"
let url = NSURL(string: "https://httpbin.org/get");
let request:NSMutableURLRequest = NSMutableURLRequest(url:url as! URL)
request.httpMethod = "GET"
request.httpBody = bodyData.data(using: String.Encoding.utf8);
NSURLConnection.sendAsynchronousRequest(request as URLRequest, queue: OperationQueue.main)
{
(response, data, error) in
if let HTTPResponse = response as? HTTPURLResponse {
let statusCode = HTTPResponse.statusCode
if statusCode == 200 {
// Yes, Do something.
let json = try? JSONSerialization.jsonObject(with: data!, options: [])
if let dictionary = json as? [String: Any] {
let args = dictionary["args"]
NSLog("args:\(args)")
for (key, value) in dictionary{
NSLog("key:\(key) value:\(value)")
}
}
}
}
}
id is a string passed in to the function.
It has valid data returned, but the test site/url also returns in json format any parameters you send it. But this snippet of code seems to not be sending the query parameters defined in bodyData and I can't figure out why.
If a GET request is used the parameters are appended to the URL and an explicit URLRequest is not needed at all.
This code is native Swift 3 and uses contemporary API:
let id = 12
let bodyData = "?sub=\(id)&name=User&email=test#test.com"
let url = URL(string: "https://httpbin.org/get" + bodyData)!
URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!)
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:Any],
let args = json["args"] as? [String:Any] {
print("args:\(args)")
for (key, value) in args{
print("key:\(key) value:\(value)")
}
}
} catch {
print(error)
}
}.resume()

Sending json array via Alamofire

I wonder if it's possible to directly send an array (not wrapped in a dictionary) in a POST request. Apparently the parameters parameter should get a map of: [String: AnyObject]?
But I want to be able to send the following example json:
[
"06786984572365",
"06644857247565",
"06649998782227"
]
You can just encode the JSON with NSJSONSerialization and then build the NSURLRequest yourself. For example, in Swift 3:
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let values = ["06786984572365", "06644857247565", "06649998782227"]
request.httpBody = try! JSONSerialization.data(withJSONObject: values)
AF.request(request) // Or `Alamofire.request(request)` in prior versions of Alamofire
.responseJSON { response in
switch response.result {
case .failure(let error):
print(error)
if let data = response.data, let responseString = String(data: data, encoding: .utf8) {
print(responseString)
}
case .success(let responseObject):
print(responseObject)
}
}
For Swift 2, see previous revision of this answer.
For swift 3 and Alamofire 4 I use the following ParametersEncoding and Array extension:
import Foundation
import Alamofire
private let arrayParametersKey = "arrayParametersKey"
/// Extenstion that allows an array be sent as a request parameters
extension Array {
/// Convert the receiver array to a `Parameters` object.
func asParameters() -> Parameters {
return [arrayParametersKey: self]
}
}
/// Convert the parameters into a json array, and it is added as the request body.
/// The array must be sent as parameters using its `asParameters` method.
public struct ArrayEncoding: ParameterEncoding {
/// The options for writing the parameters as JSON data.
public let options: JSONSerialization.WritingOptions
/// Creates a new instance of the encoding using the given options
///
/// - parameter options: The options used to encode the json. Default is `[]`
///
/// - returns: The new instance
public init(options: JSONSerialization.WritingOptions = []) {
self.options = options
}
public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var urlRequest = try urlRequest.asURLRequest()
guard let parameters = parameters,
let array = parameters[arrayParametersKey] else {
return urlRequest
}
do {
let data = try JSONSerialization.data(withJSONObject: array, options: options)
if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
}
urlRequest.httpBody = data
} catch {
throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
}
return urlRequest
}
}
Basically, it converts the array to a Dictionary in order to be accepted as Parameters argument, and then it takes back the array from the dictionary, convert it to JSON Data and adds it as the request body.
Once you have it, you can create request this way:
let values = ["06786984572365", "06644857247565", "06649998782227"]
Alamofire.request(url,
method: .post,
parameters: values.asParameters(),
encoding: ArrayEncoding())
Here is an example of encoding an Array of type Thing to JSON, using a router, and Ogra to do the JSON encoding:
import Foundation
import Alamofire
import Orga
class Thing {
...
}
enum Router: URLRequestConvertible {
static let baseURLString = "http://www.example.com"
case UploadThings([Thing])
private var method: Alamofire.Method {
switch self {
case .UploadThings:
return .POST
}
}
private var path: String {
switch self {
case .UploadThings:
return "upload/things"
}
}
var URLRequest: NSMutableURLRequest {
let r = NSMutableURLRequest(URL: NSURL(string: Router.baseURLString)!.URLByAppendingPathComponent(path))
r.HTTPMethod = method.rawValue
switch self {
case .UploadThings(let things):
let custom: (URLRequestConvertible, [String:AnyObject]?) -> (NSMutableURLRequest, NSError?) = {
(convertible, parameters) in
var mutableRequest = convertible.URLRequest.copy() as! NSMutableURLRequest
do {
let jsonObject = things.encode().JSONObject()
let data = try NSJSONSerialization.dataWithJSONObject(jsonObject, options: NSJSONWritingOptions.PrettyPrinted)
mutableRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
mutableRequest.HTTPBody = data
return (mutableRequest, nil)
} catch let error as NSError {
return (mutableRequest, error)
}
}
return ParameterEncoding.Custom(custom).encode(r, parameters: nil).0
default:
return r
}
}
}
Swift 2.0
This code below post object array.This code is tested on swift 2.0
func POST(RequestURL: String,postData:[AnyObject]?,successHandler: (String) -> (),failureHandler: (String) -> ()) -> () {
print("POST : \(RequestURL)")
let request = NSMutableURLRequest(URL: NSURL(string:RequestURL)!)
request.HTTPMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
var error: NSError?
do {
request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(postData!, options:[])
} catch {
print("JSON serialization failed: \(error)")
}
Alamofire.request(request)
.responseString{ response in
switch response.result {
case .Success:
print(response.response?.statusCode)
print(response.description)
if response.response?.statusCode == 200 {
successHandler(response.result.value!)
}else{
failureHandler("\(response.description)")
}
case .Failure(let error):
failureHandler("\(error)")
}
}
}
#manueGE 's answer is right. I have a similar approach according to alamofire github's instruction:
`
struct JSONDocumentArrayEncoding: ParameterEncoding {
private let array: [Any]
init(array:[Any]) {
self.array = array
}
func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var urlRequest = urlRequest.urlRequest
let data = try JSONSerialization.data(withJSONObject: array, options: [])
if urlRequest!.value(forHTTPHeaderField: "Content-Type") == nil {
urlRequest!.setValue("application/json", forHTTPHeaderField: "Content-Type")
}
urlRequest!.httpBody = data
return urlRequest!
}
}
`
Then call this by customize a request instead of using the default one with parameter. Basically discard the parameter, since it is a dictionary.
let headers = getHeaders()
var urlRequest = URLRequest(url: URL(string: (ServerURL + Api))!)
urlRequest.httpMethod = "post"
urlRequest.allHTTPHeaderFields = headers
let jsonArrayencoding = JSONDocumentArrayEncoding(array: documents)
let jsonAryEncodedRequest = try? jsonArrayencoding.encode(urlRequest, with: nil)
request = customAlamofireManager.request(jsonAryEncodedRequest!)
request?.validate{request, response, data in
return .success
}
.responseJSON { /*[unowned self] */(response) -> Void in
...
}
Also, the way to handle error in data is very helpful.
let url = try Router.baseURL.asURL()
// Make Request
var urlRequest = URLRequest(url: url.appendingPathComponent(path))
urlRequest.httpMethod = "post"
// let dictArray: [[String: Any]] = []
urlRequest = try! JSONEncoding.default.encode(urlRequest, withJSONObject: dictArray)
Something I do in my project to upload a JSON array
func placeOrderApi(getUserId:String,getDateId:String,getTimeID:String,getAddressId:String,getCoupon:String)
{
let data = try! JSONSerialization.data(withJSONObject: self.arrOfServices, options: [])
let jsonBatch : String = String(data: data, encoding: .utf8)!
//try! JSONSerialization.data(withJSONObject: values)
let params = [
"user_id":getUserId,
"time_id":getTimeID,
"date_id":getDateId,
"address_id":getAddressId,
"services":jsonBatch,
"payment_mode":paymentVia,
"coupon":getCoupon
] as [String : Any]
print(params)
self.objHudShow()
Alamofire.request(BaseViewController.API_URL + "place_order", method: .post, parameters: params, encoding: JSONEncoding.default)
.responseJSON { response in
debugPrint(response)
switch response.result {
case .success (let data):
print(data)
self.objHudHide()
if response.result.value != nil
{
let json : JSON = JSON(response.result.value!)
if json["status"] == true
{
}
else
{
self.view.makeToast(NSLocalizedString(json["msg"].string ?? "", comment: ""), duration: 3.0, position: .bottom)
}
}
break
case .failure:
self.objHudHide()
print("Error in upload:)")
break
}
}
}
There are 2 approach to send send JSON content as parameter.
You can send json as string and your web service will parse it on server.
d["completionDetail"] = "[{"YearOfCompletion":"14/03/2017","Completed":true}]"
You can pass each value within your json (YearOfCompletion and Completed) in form of sequential array. And your web service will insert that data in same sequence. Syntax for this will look a like
d["YearOfCompletion[0]"] = "1998"
d["YearOfCompletion[1]"] = "1997"
d["YearOfCompletion[2]"] = "1996"
d["Completed[0]"] = "true"
d["Completed[1]"] = "false"
d["Completed[2]"] = "true"
I have been using following web service call function with dictionary, to trigger Alamofire request Swift3.0.
func wsDataRequest(url:String, parameters:Dictionary<String, Any>) {
debugPrint("Request:", url, parameters as NSDictionary, separator: "\n")
//check for internete collection, if not availabale, don;t move forword
if Rechability.connectedToNetwork() == false {SVProgressHUD.showError(withStatus: NSLocalizedString("No Network available! Please check your connection and try again later.", comment: "")); return}
//
self.request = Alamofire.request(url, method: .post, parameters: parameters)
if let request = self.request as? DataRequest {
request.responseString { response in
var serializedData : Any? = nil
var message = NSLocalizedString("Success!", comment: "")//MUST BE CHANGED TO RELEVANT RESPONSES
//check content availability and produce serializable response
if response.result.isSuccess == true {
do {
serializedData = try JSONSerialization.jsonObject(with: response.data!, options: JSONSerialization.ReadingOptions.allowFragments)
//print(serializedData as! NSDictionary)
//debugPrint(message, "Response Dictionary:", serializedData ?? "Data could not be serialized", separator: "\n")
}catch{
message = NSLocalizedString("Webservice Response error!", comment: "")
var string = String.init(data: response.data!, encoding: .utf8) as String!
//TO check when html coms as prefix of JSON, this is hack mush be fixed on web end.
do {
if let index = string?.characters.index(of: "{") {
if let s = string?.substring(from: index) {
if let data = s.data(using: String.Encoding.utf8) {
serializedData = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments)
debugPrint(message, "Courtesy SUME:", serializedData ?? "Data could not be serialized", separator: "\n")
}
}
}
}catch{debugPrint(message, error.localizedDescription, "Respone String:", string ?? "No respone value.", separator: "\n")}
//let index: Int = text.distance(from: text.startIndex, to: range.lowerBound)
debugPrint(message, error.localizedDescription, "Respone String:", string ?? "No respone value.", separator: "\n")
}
//call finised response in all cases
self.delegate?.finished(succes: response.result.isSuccess, and: serializedData, message: message)
}else{
if self.retryCounter < 1 {//this happens really frequntly so in that case this fn being called again as a retry
self.wsDataRequest(url: url, parameters: parameters)
}else{
message = response.error?.localizedDescription ?? (NSLocalizedString("No network", comment: "")+"!")
SVProgressHUD.showError(withStatus: message);//this will show errror and hide Hud
debugPrint(message)
//call finised response in all cases
self.delay(2.0, closure: {self.delegate?.finished(succes: response.result.isSuccess, and: serializedData, message:message)})
}
self.retryCounter += 1
}
}
}
}
I think based on Alamofire documentation you can write the code as following:
let values = ["06786984572365", "06644857247565", "06649998782227"]
Alamofire.request(.POST, url, parameters: values, encoding:.JSON)
.authenticate(user: userid, password: password)
.responseJSON { (request, response, responseObject, error) in
// do whatever you want here
if responseObject == nil {
println(error)
} else {
println(responseObject)
}
}