Error: Must provide exactly one of these parameters: [:customer, :issuing_card] - ios

I am trying to integrate the Stripe API inside of my application using firebase cloud functions as my backend. I get the error listed above when I make a call to create an ephemeral key.
This is what my client side set up look like :
func createCustomerKey(withAPIVersion apiVersion: String, completion: #escaping STPJSONResponseCompletionBlock) {
let url = self.baseURL.appendingPathComponent("/ephemeral_keys")
Alamofire.request(url, method: .post, parameters: [
"api_version": apiVersion,"customer": "cus_somethingsomething"
])
.validate(statusCode: 200..<400)
.responseJSON { responseJSON in
switch responseJSON.result {
case .success(let json):
completion(json as? [String: AnyObject], nil)
case .failure(let error):
completion(nil, error)
}
}
}
and here is my server side index.js file look like:
exports.StripeEphemeralKeys = functions.https.onRequest((req, res) => {
const stripe_version = req.body.api_version;
const customer = req.body.customer_id;
stripe.ephemeralKeys.create(
{customer: customer},
{apiVersion: stripe_version}
).then((key) => {
res.status(200).send(key)
return admin.database().ref(`/strcustomers/tempkey`).set(key);
}).catch((err) => {
console.log('Inside error, fetching key failed', err)
});
});
I am providing a customer parameter already so I don't understand why I'm getting this error. There may be something I'm missing and could definitely use some help had anybody ran into similar issue before.
Here is the link of the tutorial I followed : https://www.iosapptemplates.com/blog/ios-development/stripe-firebase-swift

Related

Failed response from **Alamofire** in swift 5

I'm using Alamofire class for api calling. Api is working properly in Postman
please check below two screenshots for reference,
in first image data is passing inside raw body
in second image data is passing inside Headers field
now i'm using this code to call API
//for params i'm sending below parameters
//["phoneNumber":"911234567890", "countryCode" : "91"]
let headers: HTTPHeaders = [
"deviceId" : deviceId,
"osVersion": osVersion,
"deviceType": deviceType,
"resolution":resolution,
"buildNumber":buildNumber]
AF.request(strURL, method: .post, parameters: params, encoding: JSONEncoding.default, headers:headers).responseData { (response) in
switch response.result {
case .success(let data):
do {
//let asJSON = try JSONSerialization.jsonObject(with: data)
let asJSON = try JSONSerialization.jsonObject(with: data, options: [.fragmentsAllowed])
// success
print(asJSON)
let res : NSDictionary = (asJSON as AnyObject) as! NSDictionary
successBlock(res)
} catch { // error
print("decoding error:\n\(error)")
}
case .failure(let error):
print(error)
failure(error)
}
}
in all other project above code is working fine for api calling, but here i'm getting below error
{ code = 500; data = ""; message = "Failed to convert value of type 'java.lang.String' to required type 'java.util.Locale'; nested exception is java.lang.IllegalArgumentException: Locale part "en;q=1.0" contains invalid characters"; …………………… NamedValueMethodArgumentResolver.java:125)\n\t... 97 more\n"; status = "INTERNAL_SERVER_ERROR"; timestamp = "01-03-2022 07:55:20"; }
i've try several methods like URLEncoding.default, passing custom header, create custom raw request & passed header inside but nothing works,
AnyOne have solution for this issue?
Thanks in Advance.
As it is throwing error related to Local, I think some language is defined and it doesn't accept * for Accept-Language header, try sending "en" in the header Accept-Language.
Check subtags for language:
http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry :
Test Code:
func callAPI() {
let params: Parameters = ["phoneNumber":"911234567890", "countryCode" : "91"]
let headers = [
"deviceId" : "jdhcbkerfjkr",
"osVersion": "3.2.3",
"deviceType": "ANDROID",
"resolution": "122x122",
"buildNumber": "3.2.1",
"Accept-Language": "en"]
AF.request("[Test-URL]",
method: .post,
parameters: params,
encoding: JSONEncoding.default,
headers: HTTPHeaders.init(headers)).response { response in
print(String(data: response.data!, encoding: .utf8)!)
}
}

Getting bad request error in FedEx OAuth Swift

I am trying to authorised FedEx token but getting 400 error.
FedEx Developer link : https://developer.fedex.com/api/en-us/catalog/authorization/v1/docs.html#operation/API%20Authorization
Code Snippet :
let headers = [
"Content-Type": "application/x-www-form-urlencoded"
]
let parameters = [
"grant_type":"client_credentials",
"client_id":"***********************",
"client_secret":"***********************"
] as [String : Any]
Alamofire.request("https://apis-sandbox.fedex.com/oauth/token", method: .post, parameters:parameters,encoding: JSONEncoding.default, headers: headers).responseJSON {
response in
switch response.result {
case .success:
print(response)
break
case .failure(let error):
print(error)
}
}
Getting Error :
{
errors = (
{
code = "BAD.REQUEST.ERROR";
message = "Missing or duplicate parameters. Please modify your request and try again.";
}
);
transactionId = "b1d9d540-ed29-49fd-a4c2-907718e918c2";
}
From the FedEx documentation you can see that the parameters need to be sent as form-urlencoded.
And indeed, you have specified this in your headers, but then you have used a JSON encoder, so a JSON document will be sent.
Rather, use
Alamofire.request("https://apis-sandbox.fedex.com/oauth/token",method: .post, parameters: parameters, encoder: URLEncoding.default, headers: headers)

post request with body Alamofire

I am trying to post some data to the API, but I keep getting Response status code was unacceptable: 404 error message.. I have checked, the POST parameters and API Url are all correct, example request works on the postman but it is not working on Xcode..
my POST request Url is in this format: {{API}}/postData/Id/block.
my POST request function with Alamofire is as follows:
func postData(token: String, id: String, category: String, completion: #escaping(_ data: DataTobePost) -> Void) {
let header: HTTPHeaders = ["authorization": token]
let parameter: Parameters = [
"Id": id,
"category": category ]
Alamofire.request(API_Configurator.postData, method: .post, parameters: parameter, encoding: JSONEncoding.default, headers: header).validate().responseData(completionHandler: { response in
switch response.result {
case .success(let val):
do {
let data = try JSONDecoder().decode(DataTobePost.self, from: val)
completion(data)
}catch {
print("[DataTobePost Catch Error while decoding response: \(error.localizedDescription)]")
}
case .failure(let error):
print("[DataTobePost Failure Error : \(error.localizedDescription)]")
}
})
}
and the response is:
{
"success": true
}
where am i going wrong, can anyone help through this. (I am quite new to Alamofire)
There is no way to check what is wrong.
If you got the 404 error it means 2 things:
Code was written correctly(it compiles)
Requested page does not exist (404 error)
I think you need to check your API_Configurator.postData.
Usually, it's something simple like extra characters like "//", " ", "." etc.
Or the problem with API.
The best way to check API uses Postman

Postman Body Raw Request To Swift Alamofire

I'm trying to re-create this Postman settings for posting in Alamofire. This is my first time to see an API that requires both Parameters and a body with Raw Json.
I'm done with gathering and formatting my data (either in Json using SwiftyJSON or Dictionary [String : Any] / Parameters) for the said requirement.
While I did see a similar question to this: Postman request to Alamofire request but it doesn't have a valid answer. Assume that I'm quite experienced with posting/getting/etc data from various API but I just don't know how to pass raw data just like in the photo above. Please check out my comments too in the code.
Here's what I'm doing with my function for this request:
/** Apply to job with Shift.
* This service function creates a json data for applying.
*/
func someFuncService(_ job: Job, daySchedules: [(Int, String, Schedule)], withBlock completion: #escaping JobServiceCommonCallBack) {
AuthService.someFunc { (currentCustomer, accessToken) in
guard let lalala = currentCustomer?.id,
let accessT = accessToken else {
completion(LalaErrors.currentCustomerError)
return
}
guard let jobId = job.id else {
completion(LalaErrors.modelError)
return
}
let coreService = LalaCoreService()
let applicantEndpoint = LalaCoreService.Endpoint.Applicant
let parameters = [
"param1" : customerId,
"param2" : jobId,
"accessToken" : accessToken,
"shift" : self.generateDataFromDaySchedules(daySchedules) // this returns [String : Any], can be printed into Json using JSON(x)
] as Parameters
GPLog(classSender: self, log: "FINAL PARAMETER: \(parameters)")
coreService.request = Alamofire.request(
applicantEndpoint,
method: .post,
parameters: parameters,
encoding: URLEncoding.default, // I already have tried .httpbody too.
headers: nil
)
coreService.request {
(response, result) in
if let error = result?.error {
if response!.statusCode == 500 {
completion(GPKitError.newError(description: "Failed to apply. Please contact the admin."))
return
}
completion(error)
return
}
// Success
completion(nil)
return
}
}
}
EDIT: So the question is, what I'm doing wrong here? API returns me status code 500 internal server error.
coreService.request = Alamofire.request(
applicantEndpoint,
method: .post,
parameters: parameters,
encoding: URLEncoding.default, // I already have tried .httpbody too.
headers: nil
)
should be
coreService.request = Alamofire.request(
applicantEndpoint + accessToken,
method: .post,
parameters: parameters,
encoding: JSONEncoding.default,
headers: nil
)

Uploading files with Alamofire and Multer

I'm trying to upload image data from iOS using Alamofire to an Express server with Multer. req.file is undefined, and req.body is in the form { file: <bytes> }. There is no error message, but the file does not appear. Here is my code:
var bodyParser = require('body-parser')
var multer = require('multer')
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))
app.post('/api/photos/upload', function(req, res) {
var upload = multer({ dest: 'public/images/content/'}).single('file')
upload(req, res, function(err) {
if (err) {
console.log("Error uploading file: " + err)
return
}
// req.file = req.body
console.log(req.body) // form fields
console.log(req.file) // form file
})
res.json('yeah')
})
On iOS:
let url = fullURL("api/photos/upload")
Alamofire.upload(.POST, url, multipartFormData: { multipartFormData in
if let image = image {
if let imageData = UIImageJPEGRepresentation(image, 0.5) {
multipartFormData.appendBodyPart(data: imageData, name: "file")
}
}
}, encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.responseJSON { response in
switch response.result {
case .Success:
print("success")
case .Failure(let error):
print(error)
}
}
case .Failure(let encodingError):
print(encodingError)
}
})
This has puzzled me for hours, any help is greatly appreciated!
UPDATE
An HTML form worked fine through the Express endpoint, so it's definitely a problem with the request Alamofire is sending. I've tried a bunch of examples of uploading with Alamofire, but they all send the same incorrect request. There must be a way to make the same request as an HTML form but with Alamofire.
ANOTHER UPDATE
I'm now just using busboy-connect and it's working well, and with a lot more flexibility.
I was just able to get this working. It turns out that you have to specify the fileName and the mimeType using Alamofire in order for multer to pick up the upload on the server end. So, your code for adding the image should look something like this:
if let image = image {
if let imageData = UIImageJPEGRepresentation(image, 0.5) {
multipartFormData.appendBodyPart(data: imageData, name: "file", fileName: "fileName.jpg", mimeType: "image/jpeg")
}
}
Your issue is likely caused by not using multer as a middleware:
var upload = multer({ dest: 'public/images/content/'})
app.post('/api/photos/upload', upload.single('file'), function(req, res) {
// req.file should be populated now
})
In express, you can add as many middlewares as you need:
app.post('/path',
middleware1,
middleware2,
middleware3,
...,
function(req, res) {
// All middlewares has been executed
})
you know, there is difference between the method multipartFormData.append(value.data, withName: name, fileName: filename, mimeType: mimeType) and multipartFormData.append(value.data, withName: key).
when you use the former, multer will take it as req.file、the latter as req.body.

Resources