Post request with HTTP header parameters - ios

I Want to use Bittrex api. I've read their api docs. There are explanations like the following.
For this version, we use a standard HMAC-SHA512 signing. Append apikey
and nonce to your request and calculate the HMAC hash and include it
under an apisign header.
$apikey='xxx';
$apisecret='xxx';
$nonce=time();
$uri='https://bittrex.com/api/v1.1/market/getopenorders?apikey='.$apikey.'&nonce='.$nonce;
$sign=hash_hmac('sha512',$uri,$apisecret);
$ch = curl_init($uri);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('apisign:'.$sign));
$execResult = curl_exec($ch);
$obj = json_decode($execResult);
I want to do this with Swift. But I don't want to use Alamofire.
I wrote a code. I think I'm doing everything but I'm getting the following error.
{
message = "APISIGN_NOT_PROVIDED";
result = "<null>";
success = 0;
}
I wrote similar code with Delphi. It works fine. So there is no problem with APIKEY. When I use the same parameters in Delphi, the same SecretHex is generated. So there's no problem with Encryption.
I think, I cannot do the Post Request with headers.
I can not find the fault. Would you please help me.
func getBalances()
{
let apiKeySTR = "01235xxxxxx"
let secretSTR = "41691xxxxxx"
let path = "https://bittrex.com/api/v1.1/account/"
let timeInterval = NSDate().timeIntervalSince1970
let epochtime = String(floor(timeInterval))
let urlFull = path + "getbalances" + "?" + "apikey=" + apiKeySTR + "&" + "nonce=" + epochtime
let secretUInt8 : [UInt8] = Array(urlFull.utf8)
var secretKey : [UInt8]?
do {
try secretKey = HMAC(key: secretSTR, variant: .sha512).authenticate(secretUInt8)
} catch {
print ("Error")
}
let secretHex = secretKey?.toHexString() ?? ""
guard let url = URL(string: urlFull) else { return }
var request = URLRequest(url: url)
request.addValue("apising", forHTTPHeaderField: (secretHex))
request.httpMethod = "POST"
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
} catch {
print(error)
}
}
}.resume()
}

First off... you have a typo:
request.addValue("apising", forHTTPHeaderField: (secretHex))
I believe it's apisign, not "apising", right?
And below is a recap on creating REST API requests with a header and body. You can update this method according your needs:
1) Create URLRequest
var request = URLRequest(url: requestURL)
2) Set headers and http method:
request.allHTTPHeaderFields = ["Authentication" : "Bearer XYZ..."]
request.httpMethod = "POST"
3) Set request body:
// parameters is a simple [String:String] dictionary, just as header
let jsonData = try? JSONSerialization.data(withJSONObject: parameters)
request.httpBody = jsonData
Complete example:
public enum RESTMethod:String {
case get = "GET"
case post = "POST"
case put = "PUT"
}
public func sendRequest(_ url: String,
method: RESTMethod,
headers: [String : String],
parameters: [String : Any],
completionHandler: #escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionTask! {
let requestURL: URL
if method == .get {
let parameterString = parameters.stringFromHttpParameters()
requestURL = URL(string:"\(url)?\(parameterString)")!
} else {
requestURL = URL(string: url)!
}
var request = URLRequest(url: requestURL)
request.allHTTPHeaderFields = headers
request.httpMethod = method.rawValue
if method == .post {
let jsonData = try? JSONSerialization.data(withJSONObject: parameters)
request.httpBody = jsonData
}
request.timeoutInterval = 60
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
completionHandler(data,response,error)
}
task.resume()
return task
}
extension Dictionary {
/// Build string representation of HTTP parameter dictionary of keys and objects
func stringFromHttpParameters() -> String {
let parameterArray = self.map { (key, value) -> String in
let percentEscapedKey = (key as! String).addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
let percentEscapedValue = (value as? String ?? "\(value)").addingPercentEncodingForURLQueryValue()!
return "\(percentEscapedKey)=\(percentEscapedValue)"
}
return parameterArray.joined(separator: "&")
}
}
Usage:
sendRequest("http://yourserver",
method: .get, // .post or .put
headers: [],
parameters: [],
completionHandler: { (data, response, error) in
// Handle response here
})

Related

How to implement the Bearer Token to validate the API url

I set up the API and all, the only thing is Bearer Token I couldn't find any information about any code on how to implement it so it can validate the URL I am using as API.
do I need to create new swift file just for bearer token or I can write the code to the API swift file "the code below is api file"
static let shared = APICaller()
private let baseURL = "http://000.000.000.000:3030/api/"
private init() {}
var vehicles = [Vehicles]()
func getVehicles(for id: String, IMEI: Int, completed: #escaping (Result<[Vehicles],Errors>) -> Void ){
let endpoint = baseURL + "GetVehicle/?UserIdentificationValue=346HIU4623UIHG3I3I&IMEI=216216123612"
guard let url = URL(string: endpoint) else {
completed(.failure(.invalidURL))
return
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let _ = error {
completed(.failure(.unableToComplete))
return
}
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
completed(.failure(.invalidResponse))
return
}
guard let data = data else {
completed(.failure(.invalidData))
return
}
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
self.vehicles = try JSONDecoder().decode([Vehicles].self, from: data)
DispatchQueue.main.async {
completed(.failure(.invalidData))
}
} catch {
completed(.failure(.invalidData))
}
}
task.resume()
Thanks In Advance
Also I am new to swift so I would appreciate if you can tell me my API code is correct or needs any fixes since its about receiving some car info and putting into a table view cell :)
I have attached the request including headers in which you need to pass Bearer token like did in below code
let headers = [
"content-type": "application/json",
"authorizetoken": "NjQzOPA2N0NDNDFAH4CNDk3R23F2FQUY0NjV3FFE=",
"cache-control": "no-cache",
]
let parameters = ["id":"123456789"] as [String : Any]
let postData = try? JSONSerialization.data(withJSONObject: parameters, options: [])
let request = NSMutableURLRequest(url: NSURL(string: "Your URL")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 120.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as? Data
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringLocalCacheData
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData

Get request doesn't get executed in swift, getting nil value error where URL is passed in the request

I am trying to add a GET request in my application.
The values or the final url string is flowing correctly in my sURL variable. But still while executing this code I get "Found nil error" at line - "var request = URLRequest(url: URL(string: sUrl)!)"
Please help.
My code -
class AllStickerService {
static let allStickerInstance: AllStickerService = AllStickerService()
var delegateAllSticker: AllStickerProtocol!
func fetchAllSticker(category: String, APITokenString: String) {
var sUrl = "http://xyzabc.com/api/stickers"
let params = ["category": category]
var sParams = ""
for (key,value) in params {
sParams += key + "=" + value
print("\(key), \(value)")
}
if !sParams.isEmpty {
sParams = "?" + sParams
sUrl = sUrl + sParams
}
var request = URLRequest(url: URL(string: sUrl)!)
print(request)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("Bearer "+APITokenString, forHTTPHeaderField: "Authorization")
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if (response as? HTTPURLResponse) != nil {
if let httpResponse = response as? HTTPURLResponse {
print("statusCode: \(httpResponse.statusCode)")
print(httpResponse)
}
if let data = data{
do {
guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { return }
print(json)
}catch {
print("Error\(error)")
}
}
}
}.resume()
}
}
Force unwrapping is rarely a good idea. Either is using string concatenation to create URLs; Aside from potential security problems, you have to worry about things like url encoding, which is your problem here.
Your category parameter value has a space, this needs to be encoded as %20, but you don't do this and you end up with an invalid URL string. You don't see this with Postman because it is encoding the space for you behind the scenes.
A better approach is to use URLComponents, URLQueryItem and use conditional unwrapping
func fetchAllSticker(category: String, APITokenString: String) {
var sUrl = "http://xyzabc.com/api/stickers"
let params = URLQueryItem(name:"category", value: category)
if var urlComponents = URLComponents(string:"http://xyzabc.com/api/stickers") {
urlComponents.queryItems = params
if let url = urlComponents.url {
var request = URLRequest(url: url)
...
}
}
I would also recommend you look into using Decodable to handle your JSON response rather than JSONSerialization

How to Pass Key Value Parameter in JSON POST method in Swift?

This is API http://itaag-env-1.ap-south-1.elasticbeanstalk.com/filter/taggedusers/
its parameter: "contactsList" : ["5987606147", "6179987671", "5082508888"]
its header: ["deviceid": "584D97F-761A-4C24-8C4B-C145A8B8BD75", "userType": "personal", "key": "9609cc826b0d472faf9967370c095c21"]
In my code if i put breakpoint then filtertaggedUser() is calling but i am unable to go inside completionHandler the access is not going inside dataTask
Access going to else part why? the api is working.
i am trying to pass parameter key value in URL string like below
let urlStr = "http://itaag-env-1.ap-south-1.elasticbeanstalk.com/filter/taggedusers/?contactsList=" + "8908908900"
is this correct approch?
code for above API:
func filtertaggedUser() {
print("inside filter taggedusers")
let headers = ["deviceid": "584D97F-761A-4C24-8C4B-C145A8B8BD75", "userType": "personal", "key": "9609cc826b0d472faf9967370c095c21"]
let urlStr = "http://itaag-env-1.ap-south-1.elasticbeanstalk.com/filter/taggedusers/?contactsList=" + "8908908900"
let request = NSMutableURLRequest(url: NSURL(string:urlStr)! as URL,cachePolicy: .useProtocolCachePolicy,timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
// access not coming here
let httpResponse = response as? HTTPURLResponse
if httpResponse!.statusCode == 200 {
print("filter taggedusers inside")
do {
print("filter taggedusers inside do")
let jsonObject = try JSONSerialization.jsonObject(with: data!, options: .mutableLeaves) as! [String :AnyObject]
print("filter taggedusers \(jsonObject)")
} catch { print(error.localizedDescription) }
} else { Constants.showAlertView(alertViewTitle: "", Message: "Something went wrong, Please try again", on: self) }
})
dataTask.resume()
}
OUTPUT:
POSTMAN OUTPUT
POSTMAN Body
why response is not coming, where i did mistake, please help me with the code.
We can call the Post request API like below,
func getPostString(params:[String:Any]) -> String
{
var data = [String]()
for(key, value) in params
{
data.append(key + "=\(value)")
}
print(data.map { String($0) }.joined(separator: "&"))
return data.map { String($0) }.joined(separator: "&")
}
func callPostApi(){
let url = URL(string: "http://itaag-env-1.ap-south-1.elasticbeanstalk.com/filter/taggedusers/")
guard let requestUrl = url else { fatalError() }
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
request.setValue("584D97F-761A-4C24-8C4B-C145A8B8BD75", forHTTPHeaderField: "deviceid")
request.setValue("9609cc826b0d472faf9967370c095c21", forHTTPHeaderField: "key")
request.setValue("personal", forHTTPHeaderField: "userType")
let parameters = getPostString(params: ["contactsList":["8908908900"]])
request.httpBody = parameters.data(using: .utf8)
// Perform HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
let httpResponse = response as? HTTPURLResponse
print(httpResponse!.statusCode)
// Check for Error
if let error = error {
print("Error took place \(error)")
return
}
// Convert HTTP Response Data to a String
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Response data string:\n \(dataString)")
}
}
task.resume()
}
Output :
{"8908908900":{"userId":"9609cc826b0d472faf9967370c095c21","userName":"Satish Madhavarapu","profilePic":null,"oniTaag":true,"tagged":false,"userType":"personal"}}

Make Swift Class to make Http Requests

I made this class below to help make http requests from anywhere in my application, however when i call the class it does not make the request as expected. I see i can print from the function so i know it is making it that far at least. What else do i need to make this request?? the api parameter is being passed correctly as well.
in viewController:
let url = "post/test"
MakeHttpRequest.sharedInstance.postRequest(api: url)
in class:
import Foundation
final class MakeHttpRequest {
static let sharedInstance = MakeHttpRequest()
var api_token = "token_here"
var url_base = "https://test.frb.io/"
func postRequest (api : String) {
let parameters = ["email": "testing123#gmail.com"]
guard let destination = URL(string: url_base + api) else { return }
var request = URLRequest(url: destination)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
// request.setValue("clientIDhere", forHTTPHeaderField: "Authorization")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: [])
else { return }
request.httpBody = httpBody
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
if (json["response"]) != nil {
}
} catch {
print(error)
}
}
}.resume()
print(url_base + api)
}
private init() {
}
}
So two things to check. Sometimes swift function chaining doesn't work properly. So try splitting the session.dataTask and resume into two statements. And second try adding error handling to the response. You may be getting an error without knowing it. See code sample below.
import Foundation
final class MakeHttpRequest {
static let sharedInstance = MakeHttpRequest()
var api_token = "token_here"
var url_base = "https://test.frb.io/"
func postRequest (api: String, parameters: [String: Any]? = nil) {
guard let destination = URL(string: url_base + api) else { return }
var request = URLRequest(url: destination)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
// request.setValue("clientIDhere", forHTTPHeaderField: "Authorization")
if let parameters = parameters {
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else { return
}
request.httpBody = httpBody
}
let session = URLSession.shared
let task = session.dataTask(with: request) { (data, response, error) in
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
if (json["response"]) != nil {
print("1234")
} else {
print("ABCD")
}
} catch {
print(error)
}
} else {
print(error ?? "")
}
}
task.resume()
print(url_base + api)
}
private init() {
}
}
let url = "post/test"
MakeHttpRequest.sharedInstance.postRequest(api: url)

Making an HTTP POST request swift

I'm using the following function to make post an HTTP request in JSON for my application (uploading photo):
static func HTTPPostJSON(url: String,
jsonObj: AnyObject,
callback: (String, String?) -> Void) {
var request = NSMutableURLRequest(URL: NSURL(string: url)!)
request.HTTPMethod = "POST"
request.addValue("application/json",
forHTTPHeaderField: "Content-Type")
let jsonString = JSONStringify(jsonObj)
let data: NSData = jsonString.dataUsingEncoding(
NSUTF8StringEncoding)!
request.HTTPBody = data
HTTPsendRequest(request, callback)
}
jsonStringify:
static func JSONStringify(jsonObj: AnyObject) -> String {
if((jsonObj as? [Dictionary<String, AnyObject>]) != nil || (jsonObj as? [Array<AnyObject>]) != nil){
var e: NSError?
var jsonData = NSJSONSerialization.dataWithJSONObject(jsonObj, options: NSJSONWritingOptions(0), error: &e);
if e != nil {
println(e);
return "\(jsonObj)";
} else {
return NSString(data: jsonData!, encoding: NSUTF8StringEncoding)!
}
} else {
return "\(jsonObj)";
}
}
In this case, the callback function receives the parameter "Bad Request", though I don't know why it happened. Is there a better working way to make an HTTP photo post request in JSON?

Resources