How to get FedEx access token - ios

I have created development account on FedEx and get all key and secret.
Now I am trying to call oauth api but didn’t get a access token but getting error as 400.
Developer link https://developer.fedex.com/api/en-us/catalog/authorization/v1/docs.html
My code is -
let headers = [
"Content-Type": "application/x-www-form-urlencoded"
]
let parameters = [
"grant_type":"client_credentials",
"client_id":"client_id",
"client_secret":"client_secret"
] as [String : String]
let postData = try? JSONSerialization.data(withJSONObject: parameters, options: [])
let request = NSMutableURLRequest(url: NSURL(string: "https://apis-sandbox.fedex.com/oauth/token")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData! as Data
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()
}
Error Log -
(<NSHTTPURLResponse: 0x6000009b0080> { URL: https://apis-sandbox.fedex.com/oauth/token } { Status Code: 400, Headers {
"Cache-Control" = (
"no-store"
);
"Content-Length" = (
184
);
"Content-Type" = (
"application/json"
);
Date = (
"Mon, 14 Feb 2022 10:33:53 GMT"
);
Pragma = (
"no-cache"
);
Server = (
"Layer7-API-Gateway"
);
"Set-Cookie" = (
"bm_sv=0301466DB0BFD9216A1FA61DA0EC0272~1G4H2uDnGg2TFUuh7DlMXX1JIzwt6bG0fBtlySSfQAkgYesGo8P+MKPPvGVJVn8XzadxNXeGTDpjpOqQBbG1VXH6k5geeiiBP6h+AsUvs+g8hX1utfFuyRCmuHRXGO4lZKsf6jxJU2G1plXqcPPuplkB76QJgis8P9PUvXZiMZs=; Domain=.fedex.com; Path=/; Max-Age=7131; HttpOnly"
);
"server-timing" = (
"cdn-cache; desc=MISS",
"edge; dur=651",
"origin; dur=52"
);
} })

Related

Got 401 to try request login from URLSession

I have this method
func loginUser(for email: String, password: String, completed: #escaping (Result<LoginModel, Error>) -> Void) {
let endpoint = baseURL + "login"
guard let url = URL(string: endpoint) else {
completed(.failure(.invalidURL))
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
let body = ["email": email, "password": password]
let jsonData = try? JSONSerialization.data(withJSONObject: body)
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let _ = error {
completed(.failure(.unableToComplete))
return
}
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
completed(.failure(.unableToComplete))
return
}
guard let data = data else {
completed(.failure(.invalidData))
return
}
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let data = try decoder.decode(LoginModel.self, from: data)
completed(.success(data))
} catch {
completed(.failure(.invalidData))
}
}
task.resume()
}
But I try to login the user (email and password) I get a Status Code 401 and this is the all info when inspect the response.
I call this method
NetworkManager.shared.loginUser(for: emailTextField.text!, password: passwordtextField.text!) { result in
switch result {
case .success(let data):
print(data)
case .failure(let error):
print(error.rawValue)
}
}
<NSHTTPURLResponse: 0x60000181ca80> { URL: https://basee-url/api/login } { Status Code: 401, Headers {
"Access-Control-Allow-Origin" = (
"*"
);
"Cache-Control" = (
"no-cache, private"
);
Connection = (
"keep-alive"
);
"Content-Type" = (
"application/json"
);
Date = (
"Mon, 21 Jun 2021 20:11:46 GMT"
);
Server = (
Apache
);
"Transfer-Encoding" = (
Identity
);
Via = (
"1.1 vegur"
);
"X-Ratelimit-Limit" = (
60
);
"X-Ratelimit-Remaining" = (
59
);
} }
This is the request executed in Postman
I leave here the solution to the problem.
The problem into Swift code is in the request doesn't set the Application/Jason Header. Because I sent a body in json format.
Into loginUser method added this line
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")

I try to display FCM notification in background on my iPhone but it doesn't work when I send this notification with Swift

I try to display Firebase Cloud Messaging's notification in background on my iPhone but it doesn't work when I send this notification with Swift.
I send a FCM to my iPhone with a HTTP request in Postman and that's work fine: my iPhone display the notification correctly in background.
When I make the same HTTP request with Swift, the Firebase's response is fine but my iPhone don't display nothing.
There is the request and the response in Postman :
Postman's screenshot
There is the same request in a Swift Playground :
import Foundation
let key = "key=<my-server-key>"
let singleMessageUrl = "https://fcm.googleapis.com/fcm/send"
func sendSingleMessage() {
let params: [String: Any] = [
"to": "<my-device-token>",
"notificiation": [
"title": "Push from my playground",
"body": "Push from my playground !"
],
]
guard let bodyNotif = try? JSONSerialization.data(withJSONObject: params, options: []) else {
print("BAD NOTIF")
return
}
guard let json = try? JSONSerialization.jsonObject(with: bodyNotif, options: []) as? [String: Any] else {
print("BAD JSON")
return
}
print("PARAMS REQUEST:\n", params)
print("---------------------------")
print("JSON REQUEST:\n", json)
print("---------------------------")
guard let url = URL(string: singleMessageUrl) else {
print("BAD URL")
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = bodyNotif
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(key, forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
print("ERROR", error.localizedDescription)
}
guard let response = response else { return }
print("HEADERS RESPONSE:\n", response)
print("---------------------------")
guard let data = data else { return }
guard let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
print("BAD JSON RESPONSE")
return
}
print("BODY RESPONSE:\n", json)
}.resume()
}
sendSingleMessage()
When I launch the above request, the response appears to be OK in the console :
PARAMS REQUEST:
["to": "<my-device-token>", "notificiation": ["title": "Push from my playground", "body": "Push from my playground !"]]
---------------------------
JSON REQUEST:
["to": <my-device-token>, "notificiation": {
body = "Push from my playground !";
title = "Push from my playground";
}]
---------------------------
HEADERS RESPONSE:
<NSHTTPURLResponse: 0x7fcaf544c610> { URL: https://fcm.googleapis.com/fcm/send } { Status Code: 200, Headers {
"Cache-Control" = (
"private, max-age=0"
);
"Content-Encoding" = (
gzip
);
"Content-Length" = (
138
);
"Content-Type" = (
"application/json; charset=UTF-8"
);
Date = (
"Sun, 05 Jan 2020 09:47:15 GMT"
);
Expires = (
"Sun, 05 Jan 2020 09:47:15 GMT"
);
Server = (
GSE
);
"alt-svc" = (
"quic=\":443\"; ma=2592000; v=\"46,43\",h3-Q050=\":443\"; ma=2592000,h3-Q049=\":443\"; ma=2592000,h3-Q048=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000"
);
"x-content-type-options" = (
nosniff
);
"x-frame-options" = (
SAMEORIGIN
);
"x-xss-protection" = (
"1; mode=block"
);
} }
---------------------------
BODY RESPONSE:
["multicast_id": <the-multicast_id-send-by-FCM>, "results": <__NSSingleObjectArrayI 0x7ff55bd46aa0>(
{
"message_id" = "<the-message_id-send-by-FCM>";
}
)
, "success": 1, "failure": 0, "canonical_ids": 0]
But unfortunately my iPhone receive nothing whith this Swift's request while it receive correctly the notification send whith the Postman's request.
I've checked this code on my app - it works 100%. The code itself contains a force unwrapping and is copied from the Postman, so it will require optimization in the future, but you can quickly check it if you add the device token and the server key. Also I've tested your code and found one issue - you should change "notificiation" to "notification". Hope this help you.
class ViewController: UIViewController {
var semaphore = DispatchSemaphore (value: 0)
var request = URLRequest(url: URL(string: "https://fcm.googleapis.com/fcm/send")!,timeoutInterval: Double.infinity)
override func viewDidLoad() {
super.viewDidLoad()
sendSingleMessage()
}
func sendSingleMessage() {
let parameters = "{\n \"to\" : \"<my-device-token>\", \n\n \"notification\": {\n \"body\": \"From Swift code message\"\n }\n\n }"
let postData = parameters.data(using: .utf8)
request.addValue("key=<my-server-key>", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
request.httpBody = postData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print(String(describing: error))
return
}
print(String(data: data, encoding: .utf8)!)
self.semaphore.signal()
}
task.resume()
semaphore.wait()
}
}

using POST API in ios using URLSession

I'm learning IOS right now and I completely wrote same code with the tutorial. But I got an error like this
"2019-05-29 14:01:25.974883+0900 URLSessionJSONRequests[18165:938499]
Task <0EC532CF-8CA6-42C9-9BD8-6D6E74BB9C06>.<10> finished with error -
code: -1002"
My Code is this.
#IBAction func onPostTab(_ sender: UIButton) {
let parameters = ["id":"uuzaza#naver.com","pw":"1q2w3e4r"]
guard let url = URL(string:"https//taky.co.kr/login/app_login") else{return}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
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 response = response {
print(response)
}
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: [] )
print(json)
}catch{
print(error)
}
}
}.resume()
}
what is error code -1002?? I used placeholder API and it is still supported and I think the server is not the problem. Any reference or advice would be grateful!
Kindly check URL first you missed ':' after https.
Just replace your API End-point
https//taky.co.kr/login/app_login
With
https://taky.co.kr/login/app_login
After doing the above changes everything works fine.
API Response:
<NSHTTPURLResponse: 0x60000327d120> { URL: https://taky.co.kr/login/app_login } { Status Code: 200, Headers {
"Cache-Control" = (
"no-store, no-cache, must-revalidate"
);
Connection = (
"Keep-Alive"
);
"Content-Encoding" = (
gzip
);
"Content-Length" = (
93
);
"Content-Type" = (
"text/html; charset=UTF-8"
);
Date = (
"Wed, 29 May 2019 05:32:58 GMT"
);
Expires = (
"Thu, 19 Nov 1981 08:52:00 GMT"
);
"Keep-Alive" = (
"timeout=5, max=100"
);
Pragma = (
"no-cache"
);
Server = (
"Apache/2.4.18 (Ubuntu)"
);
"Set-Cookie" = (
"cookie=9f73o1c13mggukb15fq25usfpc6ms6cp; expires=Wed, 29-May-2019 09:32:58 GMT; Max-Age=14400; path=/; HttpOnly"
);
Vary = (
"Accept-Encoding"
);
} }
{
code = E01;
message = "\Uc544\Uc774\Ub514\Ub97c \Uc785\Ub825\Ud574 \Uc8fc\Uc138\Uc694.";
}

401 response when calling a 307 redirect server

I have built an iOS app calling a server which only accepts calls from whitelisted IPs (client's security requirement). They have now setup a 307 temporary redirect. I have changed the original root URL to the new redirect address and I am now getting 401 - Unauthorised access errors. Nothing else in the code has changed except for the Urls. I have tested using Postman and the calls work with the redirect address. Does anyone know what is causing this issue? I suspect that the HTTP header is being corrupted and the bearer token lost somewhere in the process.
Here is the HTTP response:
<NSHTTPURLResponse: 0x600003315840> { URL: https://"API URL HERE" } { Status Code: 401, Headers {
"Access-Control-Allow-Origin" = (
"*"
);
"Content-Length" = (
0
);
Date = (
"Wed, 06 Mar 2019 13:50:30 GMT"
);
Server = (
""
);
"Www-Authenticate" = (
Bearer
);
"X-XSS-Protection" = (
"1; mode=block"
);
} }
This is the API caller function:
func callAPI(jsonData: Data, childUrl: String, completionHandler: #escaping (_ success: Bool, _ data: Data, _ response: HTTPURLResponse) -> Void) {
let access_token = cache.access_token
let networkHeaders = [ "Content-Type": "application/json", "Authorization": access_token, "cache-control": "no-cache" ]
print(access_token)
let dataResponse = Data()
let urlResponse = HTTPURLResponse()
guard let url = URL(string: config.rootAPIUrl + childUrl) else { return }
var request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)
request.httpMethod = "POST"
request.httpBody = jsonData
request.allHTTPHeaderFields = networkHeaders
let session = URLSession.shared
session.dataTask(with: request) { data, response, error in
if error != nil {
DispatchQueue.main.async {
completionHandler(false, dataResponse, urlResponse)
}
}
if let response = response as? HTTPURLResponse, let data = data {
DispatchQueue.main.async {
completionHandler(true, data, response)
}
}
}.resume()
}
After lots of research and help from Apple. The problem was caused by the 'Authorization' value being lost from the header. The solution was to implement a redirect delegate and reattaching the header values. Here's the working code
func callAPI(jsonData: Data, childUrl: String, completionHandler: #escaping (_ success: Bool, _ data: Data, _ response: HTTPURLResponse) -> Void) {
self.jsonData = jsonData
let access_token = cache.access_token
let networkHeaders = [ "Content-Type": "application/json", "Authorization": access_token, "cache-control": "no-cache" ]
let dataResponse = Data()
let urlResponse = HTTPURLResponse()
guard let url = URL(string: config.rootAPIUrl + childUrl) else { return }
var request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)
request.httpMethod = "POST"
request.httpBody = jsonData
request.allHTTPHeaderFields = networkHeaders
let configuration = URLSessionConfiguration.default
var session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
session.dataTask(with: request) { data, response, error in
if error != nil {
DispatchQueue.main.async {
completionHandler(false, dataResponse, urlResponse)
}
}
if let response = response as? HTTPURLResponse, let data = data {
DispatchQueue.main.async {
completionHandler(true, data, response)
}
}
}.resume()
}
func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: #escaping (URLRequest?) -> Void) {
let access_token = cache.access_token
let networkHeaders = [ "Content-Type": "application/json", "Authorization": access_token, "cache-control": "no-cache" ]
guard let url = request.url else { return }
guard let jsonData = self.jsonData else { return }
var request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)
request.httpMethod = "POST"
request.httpBody = jsonData
request.allHTTPHeaderFields = networkHeaders
completionHandler(request)
}

POST request doesn't include params \ JSON

I've setup the api post request which is working fine with postman, however in my swift code it doesn't send the params with the request.
let parameters = ["spotId" : spotId,
"voteruptime" : currentDate,
"voterupid" : userId] as [String : Any]
guard let url = URL(string: "http://example.com:3000/upvote") else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("Application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else { return }
request.httpBody = httpBody
print(request.httpBody)
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()
I got a response
<NSHTTPURLResponse: 0x618000a26560> { URL: http://example.com:3000/upvote } { status code: 200, headers {
Connection = "keep-alive";
"Content-Length" = 28;
"Content-Type" = "application/json; charset=utf-8";
Date = "Sat, 21 Oct 2017 03:11:46 GMT";
Etag = "W/\"1c-BWaocQVSSeKjLiaYjOC8+MGSQnc\"";
"X-Powered-By" = Express;} }
{
n = 0;
nModified = 0;
ok = 1;
}
The server code Node JS is:
app.post('/upvote', function(req, res){
Spots.update({_id: req.query.spotId},{$push:{'upvotes':{'voterupid':req.query.voterupid,'voteruptime':req.query.voteruptime}}},function( err, Spots){
console.log(req.url)
if(err){
throw err;
}
res.json(Spots);
});
});
I tried also alamofire, and it's the same issue, no params sent to the server.
I believe the issue is that req.query accesses data passed on the query string, whereas you are POSTing the data in the body of the request.
To access the body, you need to use body-parser as described in multiple answers here: How to access the request body when POSTing using Node.js and Express?

Resources