Making a request with Alamofire (swift 4) to an api endpoint (form encoded content type) and passing a username and password via login. When testing in POSTMAN, this endpoint works without errors and returns valid JSON (see below).
My swift code is as follows:
let headers = [
"content-type": "application/x-www-form-urlencoded",
"cache-control": "no-cache"
]
let parameters = [
"username": "user#user.com",
"password": "password"
]
Alamofire.request("https://xxxxx.com/api/login/", method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: headers).responseJSON { response in
print(response)
}
The response I get is as follows:
FAILURE: responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}))
Any insight would be appreciated!
Change JSONEncoding.default to URLEncoding.default as below,
Alamofire.request("https://xxxxx.com/api/login/", method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers).responseJSON { response in
print(response)
}
Related
Is it possible to use Alamofire like so:
AF.request("https://api.smartsheet.com/2.0/sheets/",method: .get).responseJSON { Data in debugPrint(Data.result) }
in Swift to interact with the Smartsheet API?
I'd hope that swapping out the current https with an reasonable one would do what I want.
I would like to get information from the API. The error thrown is that I don't have authorization for the API:
Swift.Result<Any, Alamofire.AFError>.success({ errorCode = 1004; message = "You are not authorized to perform this action."; refId = 1ca40zco0itdd; }).
I just needed to understand end points better and read the documentation on Alamofire. I changed my code to the following and it worked!
let headers: HTTPHeaders = [
"Authorization": "Bearer " + api_key_smartsheet,
"Accept": "application/json"
]
AF.request("https://api.smartsheet.com/2.0/sheets/?includeAll=True", method: .get,headers: headers).responseJSON { response in
debugPrint(response)
}'''
I want to request a token via cURL using Swift Alamofire. However, I could not figure out so far how to pass on the right parameters in the right order to make it work.
The description given by Amadeus is the following:
let headers = [
"Content-Type": "application/x-www-form-urlencoded"
]
let params = [
"grant_type": "client_credentials"
]
Alamofire.request("https://test.api.amadeus.com/v1/security/oauth2/token", method: .post, parameters: params, encoding: JSONEncoding.default, headers: headers).authenticate(user: "API", password: "API").responseJSON { response in debugPrint(response)
let result = response.result.value
print(result)
}
The expected result is to get JSON file in return including the token to make API requests. any help is highly appreciated. Thanks
Let's make use of usefull debug tools of Alamofire since you have a cURL sample.
Let's break your current code:
let headers = ["Content-Type": "application/x-www-form-urlencoded"]
let params = ["grant_type": "client_credentials"]
let request = Alamofire.request("https://test.api.amadeus.com/v1/security/oauth2/token",
method: .post,
parameters: params,
encoding: JSONEncoding.default,
headers: headers).authenticate(user: "API", password: "API")
print(request.debugDescription)
request.responseJSON { response in
debugPrint(response)
let result = response.result.value
print(result)
}
Output:
$>curl -v \
-X POST \
-u API:API \
-H "Accept-Language: fr-US;q=1.0, en;q=0.9, fr-FR;q=0.8" \
-H "Accept-Encoding: gzip;q=1.0, compress;q=0.5" \
-H "User-Agent: iOSTest/1.0 (nt.iOSTest; build:1; iOS 12.2.0) Alamofire/4.8.1" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "{\"grant_type\":\"client_credentials\"}" \
"https://test.api.amadeus.com/v1/security/oauth2/token"
Let's go piece by piece:
We should forget about Accept-Encoding, User-Agent & Accept-Language headers. I'll skip them later.
We see that the -d (data into httpBody) is wrong.
Let's change that: encoding: JSONEncoding.default to encoding: URLEncoding(destination: .httpBody). Plus it makes sense since in the content type we said it was url encoded.
We get then:
$>-d "grant_type=client_credentials"
Seems better.
We see the -u API:API \ which correspond to .authenticate(user: "API", password: "API"). We might want to remove it if the server doesn't manage authentification like that and put it into the params instead.
So now, let's change the params:
let params = ["grant_type": "client_credentials",
"client_id" : "APIKey",
"client_secret" : "APISecret"]
We get:
$>-d "client_id=APIKey&client_secret=APISecret&grant_type=client_credentials" \
It should work then.
The order is not the same, but server shouldn't care about it. It should be a key/access not an index/access.
So final:
let headers = ["Content-Type": "application/x-www-form-urlencoded"]
let params = ["grant_type": "client_credentials",
"client_id" : "APIKey",
"client_secret" : "APISecret"]
let request = Alamofire.request("https://test.api.amadeus.com/v1/security/oauth2/token",
method: .post,
parameters: params,
encoding: URLEncoding(destination: .httpBody),
headers: headers)
print(request.debugDescription)
request.responseJSON { response in
debugPrint(response)
let result = response.result.value
print(result)
}
Output (with skipped headers):
$ curl -v \
-X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=APIKey&client_secret=APISecret&grant_type=client_credentials" \
"https://test.api.amadeus.com/v1/security/oauth2/token"
The docs say that the parameters should include grant_type:client_credentials&client_id={client_id}&client_secret={client_secret}. Your parameters are missing the client ID and client secret. Make sure to include those by doing something like this:
let params = [
"grant_type": "client_credentials&client_id=CLIENTIDHERE&client_secret=CLIENTSECRETHERE"
]
The string that has to be passed as body is:
let params = [
"grant_type=client_credentials&client_id=CLIENTIDHERE&client_secret=CLIENTSECRETHERE"
]
I don't know much about Swift but I guess you could do:
let params = [
"grant_type": "client_credentials"
"client_id" : "Your API Key"
"client_secret" : "Your API Secret"
]
I'm sending a request to an API, but it always responds with an error Not readable http body.
In message it returns:
exception = "class org.springframework.http.converter.HttpMessageNotReadableException";
httpCode = 400;
httpMessage = "Bad Request";
Could not read document: Unrecognized token 'product': was expecting ('true', 'false' or 'null')\n at [Source: java.io.PushbackInputStream#430128e1; line: 1, column: 9]; nested exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'product': was expecting ('true', 'false' or 'null')\n at [Source: java.io.PushbackInputStream#430128e1; line: 1, column: 9]
But product isn't boolean, but string.
Anyone know, what's wrong?
let api_key = Data(klic.utf8).base64EncodedString()
let parametry = ["product" : "STANDART"] as [String : Any]
let headers = ["authorization" : "Basic \(api_key)", "content-type" : "application/json", "cache-control" : "no-cache"]
Alamofire.request("https://stage.japostparcel.cz/api/v1/order/", method: .post, parameters: parametry, headers: headers).responseJSON { (response) in
//print(NSString(data: (response.request?.url)!, encoding: String.Encoding.utf8.rawValue))
print(response)
}
Your base url ends with order/ so you post something like order/?product= STANDART. I am pretty sure you need some kind of page ref in between and not /? something like
`order/order_page?product= STANDART`
So check the documentation
I am trying to receive an access token from PayPal's server using the authorization code in a Sandbox environment. I believe the problem is in converting curl to an Alamofire request, but I'm not sure. Any help is appreciated.
Here is my code for sending authorization to server:
func sendAuthorizationToServer(authorization: [AnyHashable: Any]) {
let jsonAuth = JSON(authorization)
let headers = [
"content-type": "application/x-www-form-urlencoded; charset=utf-8",
]
let parameters = [
"client_id": Constants.payPalSandboxID,
"client_secret": Constants.payPalSandboxSecret,
"grant_type": "authorization_code",
"redirect_uri": "urn:ietf:wg:oauth:2.0:oob",
"code": jsonAuth["response"]["code"].stringValue
]
Alamofire.request("https://api.sandbox.paypal.com/v1/oauth2/token", method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers).responseJSON { response in
print(response.request)
print(response.response)
print(response.data)
print(response.error)
}
}
I've checked jsonAuth["response"]["code"].stringValue and it is returning a correct authorization code.
My doubts are if it should be a .post request or a .get request, and if my credentials in the parameters are in the correct order/structure.
Here is the output of the last print statements:
Here is the SDK link for exchanging an authorization code for the access token:
https://github.com/paypal/PayPal-iOS-SDK/blob/master/docs/future_payments_server.md#exchange-authorization-code-for-refresh--access-tokens
import SwiftyJSON
import Alamofire
// ... ...
// ... ...
// ... ...
let credentialData = "\(paypalClientId):\(paypalSecret)".data(using: String.Encoding.utf8)!
let base64Credentials = credentialData.base64EncodedString(options: [])
let headers = [
"Authorization": "Basic \(base64Credentials)",
]
let params:[String: Any] = [
"grant_type": "client_credentials",
]
Alamofire.request(tokenAPI, method: .post, parameters: params, encoding: URLEncoding.default, headers: headers)
.validate()
.responseJSON { (response) in
debugPrint(response)
switch response.result {
case .success(let data):
let json = JSON(data)
let accessToken = json["access_token"].stringValue
break;
case .failure(let error):
debugPrint(error)
debugPrint(response.data)
}
}
Please note that encoding must be URLEncoding.default not the JSONEncoding.default
I'm trying to recreate a POST request that already works in Postman in Swift 3 with Alamofire 4, but i'm always getting a Status Code 400 "Bad Request". I am out of ideas about what I'm doing wrong here.
This is the request in Postman, additionally there is a username and password in the Body in JSON format:
Reading the Docs for Alamofire, I thought this should be the correct Swift code:
func login(as username: String, withPassword password: String) {
let url = "https://api2.drive-now.com/login"
let parameters: Parameters = [
"username" : username,
"password" : password
]
let loginHeaders: HTTPHeaders = [
"Accept" : "application/json;v=1.6",
"Accept-Encoding" : "gzip, deflate, sdch",
"Accept-Language" : "de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4",
"Connection" : "keep-alive",
"Host" : "api2.drive-now.com",
"Origin" : "https://de.drive-now.com",
"X-Api-Key" : "adf51226795afbc4e7575ccc124face7",
"X-Language" : "de",
"Content-Type" : "application/json"
]
Alamofire.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: loginHeaders).responseJSON { response in
print("Request: \(response.request)") // original URL request
print("Response: \(response.response)") // HTTP URL response
print("Data: \(response.data)") // server data
print("Result: \(response.result)") // result of response serialization
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}
}
My console output is:
Request: Optional(https://api2.drive-now.com/login)
Response: Optional(<NSHTTPURLResponse: 0x6000000266a0> { URL: https://api2.drive-now.com/login } { status code: 400, headers {
Connection = close;
"Content-Length" = 181;
"Content-Type" = "text/html";
Date = "Tue, 13 Dec 2016 22:12:46 GMT";
Server = "nginx/1.4.6 (Ubuntu)";
} })
Data: Optional(181 bytes)
Result: FAILURE
Is there a custom session manager maybe that I have to implement? Or do you know of any debugging methods I could use here?
A friend accustomed to the API did help me resolve the issue: it was a default header field that seems to be added by Alamofire to every call. The API didn't accept calls with a "User-Agent" set (don't ask me why).
To help others who might have the same problem, I share the steps I went through to find and resolve the issue:
I made Alamofire.request(...) into a variable named postage (you can call it however you like, of course)
I added debugPrint(postage) to the end of the login-function
The output showed the additional header field
I constructed a custom SessionManager like below
var headers = Alamofire.SessionManager.defaultHTTPHeaders
headers.removeValue(forKey: "User-Agent")
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = headers
api = Alamofire.SessionManager(configuration: configuration)