React Native: Fetch Stripe API - react-native

I'm attempting to fetch() Stripe's API to create a payment token directly from the front-end with React Native.
I'm doing so with the following:
const genCard = {
'card[number]': "4242424242424242",
'card[exp_month]': "11",
'card[exp_year]': "25,
'card[cvc]': "111"
}
var formBody = []
for (var property in genCard) {
var encodedKey = encodeURIComponent(property)
var encodedValue = encodeURIComponent(genCard[property])
formBody.push(encodedKey + "=" + encodedValue)
}
formBody = formBody.join("&")
const result = fetch("https://api.stripe.com/v1/tokens", {
method: "post",
headers: {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
Authorization: "Bearer " + "sk_test_4eC39HqLyjWDarjtT1zdp7dc",
},
body: formBody
}).then(response => response.json())
console.log('logging: \n', genCard, '\n', formBody, '\n', result)
The logging output gives me the following:
logging:
{"card[cvc]": "111", "card[exp_month]": "11", "card[exp_year]": "25", "card[number]": "4242424242424242"}
card%5Bnumber%5D=4242424242424242&card%5Bexp_month%5D=11&card%5Bexp_year%5D=25&card%5Bcvc%5D=111
{"_40": 0, "_55": null, "_65": 0, "_72": null}
genCard contains all the CC data required by Stripe (number, exp_month, exp_year, cvc), and formBody formats the CC data in accordance to all the documentation and guides I've found online. However, the API response I'm receiving is not the expected payment token, but instead {"_40": 0, "_55": null, "_65": 0, "_72": null}.
I believe I've followed Stripe's documentation, but either the header data is incorrect or the body data is mis-formatted.
Is anybody familiar with this process? What am I missing?

For anybody interested, the following solution worked:
async function testStripe() {
const genCard = {
'card[number]': "4242424242424242",
'card[exp_month]': "11",
'card[exp_year]': "25,
'card[cvc]': "111"
}
const results = await fetch("https://api.stripe.com/v1/tokens", {
method: "post",
headers: {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
Authorization: "Bearer " + "sk_test_4eC39HqLyjWDarjtT1zdp7dc",
},
body: Object.keys(genCard)
.map(key => key + '=' + genCard[key])
.join('&'),
}).then(response => response.json())
console.log('\n\n\nlogging: \n', genCard, '\n', 'blank', '\n', results)
return
}
Wrap your fetch in an async function and await the results
The fetch body must be key->value pairs of the card data
Use your Stripe Publishable Key to authenticate api requests
Your api response should look something like this:
{"card": {"address_city": null, "address_country": null, "address_line1": null, "address_line1_check": null, "address_line2": null, "address_state": null, "address_zip": null, "address_zip_check": null, "brand": "Visa", "country": "US", "cvc_check": "unchecked", "dynamic_last4": null, "exp_month": 11, "exp_year": 2022, "fingerprint": "Xt5EWLLDS7FJjR1c", "funding": "credit", "id": "card_1INjaU2eZvKYlo2C5O5qqIFW", "last4": "4242", "metadata": {}, "name": null, "object": "card", "tokenization_method": null}, "client_ip": "66.42.75.92", "created": 1614020214, "id": "tok_1INjaU2eZvKYlo2CDjL8bde4", "livemode": false, "object": "token", "type": "card", "used": false}

Related

issues with fetching data from rapid API, using fetch-node

I've copied the demo code off their site but it seems that I can't crack it, I've never got this error, Used double quotes and without quotes on the keys in the post options, still getting this error.
const res = await fetch("https://textanalysis-keyword-extraction-v1.p.rapidapi.com/keyword-extractor-text", {
"method": "POST",
"headers": {
"content-type": "application/x-www-form-urlencoded",
"x-rapidapi-key": "ksjadkasjkasjkfjhjafkakjkajkasjf", // hidden key
"x-rapidapi-host": "textanalysis-keyword-extraction-v1.p.rapidapi.com"
},
"body": {
"text": "Keyword extraction is tasked with the automatic identification of terms that best describe the subject of a document. Key phrases, key terms, key segments or just keywords are the terminology which is used for defining the terms that represent the most relevant information contained in the document. Although the terminology is different, function is the same",
"wordnum": "5"
}
})
.then(response => {
console.log(response);
console.log(response.headers);
})
.catch(err => {
console.error(err);
});
Here is the error, apparently it's something to with "[Symbol(Body internals)]" coming out as an empty object
Response {
size: 0,
timeout: 0,
[Symbol(Body internals)]: {
body: PassThrough {
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
_writableState: [WritableState],
allowHalfOpen: true,
[Symbol(kCapture)]: false,
[Symbol(kCallback)]: null
},
disturbed: false,
error: null
},
[Symbol(Response internals)]: {
url: 'https://textanalysis-keyword-extraction-v1.p.rapidapi.com/keyword-extractor-text',
status: 400,
statusText: 'Bad Request',
headers: Headers { [Symbol(map)]: [Object: null prototype] }, // error code
counter: 0
}
}
Generally, a 404 code indicates malformed request syntax, invalid request message framing, or deceptive request routing.
But everything looks good in the code snippet that you have posted above. Try this:
fetch("https://textanalysis-keyword-extraction-v1.p.rapidapi.com/keyword-extractor-text", {
"method": "POST",
"headers": {
"content-type": "application/x-www-form-urlencoded",
"x-rapidapi-host": "textanalysis-keyword-extraction-v1.p.rapidapi.com",
"x-rapidapi-key": ""
},
"body": {
"wordnum": "5",
"text": ""
}
})
.then(response => {
console.log(response);
})
.catch(err => {
console.error(err);
});
You can always get in touch with the support team at support#rapidapi.com

React native sending image to server using formdata

I have a problem sending a picture to a server, that's like the default approach, but it does not seem to work.
var source = '/Users/alexx/Library/Developer/CoreSimulator/Devices/44F0FA92-4898-4CFB-862E-4E5EC4C8AB28/data/Containers/Bundle/Application/34BCE695-4B4F-472F-AB5C-F2336AC45273/DoorLock.app/123.jpg';
const form = new FormData();
form.append('image', {
uri: source,
type: 'image/jpg',
name: '123.jpg',
});
const data = () => {
fetch(api ,{
method: 'POST',
body: form,
})
that's the response i get from the server:
{
"_bodyBlob": {
"_data": {
"__collector": [
Object
],
"blobId": "78B18938-15BF-4F18-B3C8-1EB30A24D9F8",
"name": "test.html",
"offset": 0,
"size": 192,
"type": "text/html"
}
},
"_bodyInit": {
"_data": {
"__collector": [
Object
],
"blobId": "78B18938-15BF-4F18-B3C8-1EB30A24D9F8",
"name": "test.html",
"offset": 0,
"size": 192,
"type": "text/html"
}
},
"bodyUsed": false,
"headers": {
"map": {
"connection": "keep-alive",
"content-length": "192",
"content-type": "text/html",
"date": "Mon, 02 Nov 2020 22:57:21 GMT",
"server": "PythonAnywhere"
}
},
"ok": false,
"status": 400,
"statusText": undefined,
"type": "default",
"url": api
}
Although this python code works perfectly and gets a correct response
img = {'file':('123.png', open('the path to the pic/123.png', 'rb'), 'image/png)}
post(api, files = img)
is there any way to get this working or its the server side problem that can't receive the correct arguments?
Adding "file://" to the beginning of the source string fixed the problem.
so the src looks like
var source = 'file:///Users/alexx/Library/Developer/CoreSimulator/Devices/44F0FA92-4898-4CFB-862E-4E5EC4C8AB28/data/Containers/Bundle/Application/34BCE695-4B4F-472F-AB5C-F2336AC45273/DoorLock.app/123.jpg';
then it fetches perfectly, hope it helps anybody who tries to send a local image using formdata, the summary looks like this now
const form = new FormData();
form.append('file', {
uri: source,
name: '123.jpg',
fileName: 'file', //optional
});
fetch(uri,{
method: 'post',
body: form,
})
.then(response => {
console.log("image uploaded")
console.log(response)
})
.catch(console.log);
In Formdata when you pass files, you need to pass 3 parameters where
key expected from the backend (in your case image).
It will be an object which has three properties named name, type, and uri where type is the mime type (ex: image/jpeg).
name of the file
Eg:
data.append("FilePath",{
name:"image.png",
type:"image/png",
uri:"content://com.camera/image.png"
},image.png)

Agora Unable to Start Cloud Recording

options1 = {
'method': 'POST',
'url': 'https://api.agora.io/v1/apps/' + appID + '/cloud_recording/resourceid/' + resourceId + '/mode/2/start',
'headers': {
'Content-Type': 'application/json',
'Authorization': 'Basic XXX'
},
body: JSON.stringify({
"cname": "lol",
"uid": "1",
"clientRequest": {
"token": token,
"recordingConfig": {
"maxIdleTime": 30,
"streamTypes": 2,
"channelType": 0,
"videoStreamType": 0,
"transcodingConfig": {
"height": 640,
"width": 360,
"bitrate": 500,
"fps": 15,
"mixedVideoLayout": 1,
"backgroundColor": "#FF0000"
},
"subscribeVideoUids": [
"123",
"456"
],
"subscribeAudioUids": [
"“123”",
"“456”"
],
"subscribeUidGroup": 0
},
"recordingFileConfig": {
"avFileType": [
"hls"
]
},
"storageConfig": {
"accessKey": config.writeAccessKeyId,
"region": 3,
"bucket": config.bucket,
"secretKey": config.writeSecretAccessKey,
"vendor": 1,
"fileNamePrefix": [
"directory1",
"directory2"
]
}
}
})
};
request(options1, function (error, response, body) {
if (error) throw new Error(error);
console.log(response.statusCode);
I referred to the Agora's Cloud Recording API. Authentication and resourceId work fine. The response.statusCode is always 404. Unable to locate the error. I tested on Postman and the URL is not working as well. May I know if any attributes are entered wrongly? Does the user have to join the channel before the recording can start?
In your url, you have specified mode/2/start.
It should be mode/mix/start.
You can refer the documentation here for more information:
https://docs.agora.io/en/cloud-recording/cloud_recording_api_rest?platform=All%20Platforms#parameters-1
Does cloud recording work for Android and iOS as well?

Using Stripe webhooks with graphql-yoga and Prisma

I'm having some trouble finding how to intercept Stripe webhook calls in my application. I use graphql-yoga (express) and prisma.
I have to listen to payment failure calls from Stripe so I can edit the corresponding user profile.
Thanks for the help!
Stripe webhook calls look like so :
{
"created": 1326853478,
"id": "charge.expired_00000000000000",
"type": "charge.expired",
"object": "event",
"request": null,
"pending_webhooks": 1,
"data": {
"object": {
"id": "ch_00000000000000",
"object": "charge",
"amount": 100,
"captured": false,
"created": 1537153592,
"currency": "usd",
"customer": null,
"description": "My First Test Charge (created for API docs)",
"invoice": null,
"livemode": false,
"on_behalf_of": null,
"order": null,
"outcome": null,
"paid": true,
"receipt_email": null,
"receipt_number": null,
"refunded": false,
"review": null,
"shipping": null,
"source": {
"id": "card_00000000000000",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": "12919",
"address_zip_check": "pass",
"brand": "Visa",
"country": "US",
"customer": "cus_00000000000000",
"cvc_check": null,
"name": null,
"tokenization_method": null
},
"statement_descriptor": null,
"status": "succeeded",
}
}
}
Since Stripe Webhook returns a generic http POST with JSON payload, it will not format the event data according to Graphql language query.
For now, what you can do is to expose a normal REST API endpoint using Graphql-Yoga's express[0]
I have composed a working sample code you can try it out
const { GraphQLServer } = require('graphql-yoga')
const typeDefs = `
type Query {
hello(name: String): String!
}
`
const resolvers = {
Query: {
hello: (_, { name }) => `Hello ${name || 'World'}`,
},
}
const server = new GraphQLServer({ typeDefs, resolvers, skipValidation: true })
server.express.use('/api/stripe/webhooks', (req, res) => {
// Handle your callback here !!!!
res.status(200).send();
})
server.start(() => console.log('Server is running on localhost:4000'))
Let me know if the above helps.
[0] https://github.com/prisma/graphql-yoga#how-to-eject-from-the-standard-express-setup

React Native use Twitter search API with Application-only authentication

I am new to React Native and want to build an App that uses the Twitter search API to display Tweets. No need for User Authentication.
I've been struggling the last two nights to get this working and starting to get frustrated xD.
I've tried building the request using Fetch and XMLHttpRequest with no luck. Also I tried several packages enabling OAuth 2.0 which also didn't work. I have the feeling I'm over complicating things as all I want to do is use the Application-only authentication and use the Standard search API.
Does anyone out there please have a code snippet on how to do this in react native without any extra packages? Is it possible at all with "just" Fetch or XMLHttpRequest?
Thanks in advance
Edit: Here's my code so far
var base64 = require('base-64');
var credentials = encodeURIComponent(key) + ":" + encodeURIComponent(secret);
var encoded = new Buffer(credentials).toString('base64');
console.log(encoded);
fetch('https://api.twitter.com/oauth2/token', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
'Authorization': 'Basic ' + encoded
},
body: {
'grant_type': 'client_credentials'
},
}).then((response) => console.log(response))
Here the response:
Response {
"_bodyBlob": Blob {
"_data": Object {
"blobId": "8dea4e53-7b39-4b78-b1a5-d7ef5a58de48",
"offset": 0,
"size": 114,
},
},
"_bodyInit": Blob {
"_data": Object {
"blobId": "8dea4e53-7b39-4b78-b1a5-d7ef5a58de48",
"offset": 0,
"size": 114,
},
},
"headers": Headers {
"map": Object {
"cache-control": Array [
"public, max-age=0",
],
"content-disposition": Array [
"attachment; filename=json.json",
],
"content-type": Array [
"application/json;charset=utf-8",
],
"date": Array [
"Wed, 16 May 2018 16:55:48 GMT",
],
"expires": Array [
"Tue, 31 Mar 1981 05:00:00 GMT",
],
"last-modified": Array [
"Wed, 16 May 2018 16:55:48 GMT",
],
"ml": Array [
"A",
],
"server": Array [
"tsa_o",
],
"status": Array [
"403 Forbidden",
],
"strict-transport-security": Array [
"max-age=631138519",
],
"x-connection-hash": Array [
"b6dde5b876b934c8dcdb059ef0c400fa",
],
"x-content-type-options": Array [
"nosniff",
],
"x-frame-options": Array [
"DENY",
],
"x-response-time": Array [
"105",
],
"x-transaction": Array [
"0084737c0054c4dc",
],
"x-tsa-request-body-time": Array [
"26",
],
"x-twitter-response-tags": Array [
"BouncerCompliant",
],
"x-ua-compatible": Array [
"IE=edge,chrome=1",
],
"x-xss-protection": Array [
"1; mode=block; report=https://twitter.com/i/xss_report",
],
},
},
"ok": false,
"status": 403,
"statusText": undefined,
"type": "default",
"url": "https://api.twitter.com/oauth2/token",
}
So, I'm happy to report I got this working.
Main problem was the encoding of the Request Body.
Here"s the working code to authenticate and get a bearer token. Then using this token to use the search API:
_getBearer = () => {
var details = {
'grant_type': 'client_credentials'
};
var formBody = [];
for (var property in details) {
var encodedKey = encodeURIComponent(property);
var encodedValue = encodeURIComponent(details[property]);
formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");
var key = "xxx";
var secret = "yyy";
var base64 = require('base-64');
var credentials = encodeURIComponent(key) + ":" + encodeURIComponent(secret);
var encoded = new Buffer(credentials).toString('base64');
console.log("Created encoded credentials: " + encoded);
fetch('https://api.twitter.com/oauth2/token', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
'Authorization': 'Basic ' + encoded
},
body: formBody
}).then((response) => response.json())
.then((responseData) => {
bearerToken = responseData.access_token;
console.log("Got Bearer: " + responseData.access_token);
this._loadTweet();
})
.catch((error) => {
console.error(error);
Alert.alert('Alert Title failure' + JSON.stringify(error))
});
_loadTweet = () => {
console.log("start load tweet");
fetch('https://api.twitter.com/1.1/search/tweets.json?q=love', {
method: 'GET',
headers: {
'Authorization': "Bearer " + bearerToken
}
}).then((response) => response.json())
.then((responseData) => {
console.log(JSON.stringify(responseData));
})
.catch((error) => {
console.error(error);
Alert.alert('Alert Title failure' + JSON.stringify(error))
});
};
};