Github API update json file - base64

I'm using the Github Contents API to update a .json file within a repo, but it doesn't seem to work as expected. This is a client-side (browser) request.
Basically, I have a json file and I would like to add a new JSON object to it. The structure of the object is
id: ''
isEnabled: true
With the Contents API I am able to create the commit but it sort of looks like this -
This is the code that is responsible for creating and pushing the commit object
let updatedContent = utf8.decode(base64.encode(modifiedContent));
console.log(updatedContent);
// const commit = await fetch(
// `${GITHUB_HOST}/repos/${OWNER}/${REPO}/contents/src/components.json`,
// {
// method: 'PUT',
// headers: AuthService.getAuthServiceInstance().withGithubAuthHeaders({
// 'Content-Type': 'application/json',
// }),
// body: JSON.stringify({
// path: 'src/components.json',
// content: updatedContent,
// sha,
// message,
// branch: activeBranch,
// }),
// }
// );
I'm not sure what I'm doing incorrect in this case.

Assuming modifiedContent is a valid JSON Object:
For NodeJS:
const updatedContent = Buffer.from(JSON.stringify(modifiedContent), "utf8").toString("base64")
For Browser:
const updatedContent = btoa(JSON.stringify(content))
Then proceed to construct your request as you've shown above.
To use the API you've mentioned, you're code would look something like:
const originalContent = await getFromOrigin(...);
const modifiedContent = await getUpdatedContentFromEditor(...);
const updatedContent = btoa(modifiedContent);
Edit 1: Added the browser and NodeJS variants.
Edit 2: Added more context.

Related

How to send a file to backend in react-native using node.js

I tried
const myData = uri; // this looks like file:///data/expo/...
const myDataResponse = await API.SendFile({
myData: myData
});
But file is not being recieved in the backend. Is there any other way to do this?
IN the backend I get
console.log(req.body)
// I get a string same as uri of file
console.log(req.file)
// undefined
Backend is setup perfectly. I am getting successful response when using postman.
Any help is appreciated. I am a begginer.
You should use FormData.
const data = new FormData();
// first argument is the key name received on you API
// second argument is your file path
data.append('file', filePath)
// then your request should look like this :
await fetch(url, {
method: 'post',
headers: {
'Content-Type': 'multipart/form-data',
},
body: data,
})

Issue With Passing FormData in Vue.js to Netlify Lambda via POST, and Then to CF7 WordPress Endpoint

I'm not knowledgeable enough to know all the ins and outs of formatting data for http requests. I'm trying to send FormData from a vue.js app into a netlify serverless function (lambda) and then pass that FormData along to my Contact Form 7 WordPress plugin REST API.
I managed to get my FormData passed to my lambda using JSON.stringify, and when I JSON.parse the data seems to be intact. I then used form-data in node to build a new FormData object to pass.
I noticed however that I'm unable to console.log it's contents using the client-side method of:
// I get values is not a function
for (var value of formData.values()) {
console.log('>> VALUE = ',value);
}
// I get entries is not a function
for (var pair of formData.entries()) {
console.log(pair[0]+ ', ' + pair[1]);
This is a red flag to me, telling me that FormData in node might not be handled the same as FormData in my vue.js code..
When I try to hit my Contact Form 7 endpoint with the data, I get an error in my response saying that one or more of my fields are in error, even though it seems to look ok to me, so something is up, but I've been banging my head against the wall trying to determine what the solution is.
My gut is telling me that there's something I need to do still, to format the data, or send the data in a way that Contact Form 7 is expecting..
Earlier in my project history, when I ran an axios.post in vue.js (not using netlify lambda) it worked and my contact form emails were sending, so I know I'm hitting the right endpoint with the right codes/data.
Here is all the relevant code I'm using for this project:
// --------------------------------------------
// in my vue.js component:
// --------------------------------------------
this.bodyFormData = new FormData()
this.bodyFormData.append( 'your-name', this.value_name )
this.bodyFormData.append( 'tel-725', this.value_phone )
this.bodyFormData.append( 'your-email', this.value_email )
this.bodyFormData.append( 'your-subject', this.value_subject )
this.bodyFormData.append( 'your-message', this.value_message )
// (...)
let theFormData = JSON.stringify(Object.fromEntries(this.bodyFormData))
Vue.prototype.$http.post('/.netlify/functions/myfunction',{token:token, formData:theFormData})
// --------------------------------------------
// in my netlify serverless lambda function myfunction.js :
// --------------------------------------------
const axios = require('axios');
const FormData = require('form-data');
const AUTH_API_ENDPOINT = 'https://www.####.com/wp-json/jwt-auth/v1/token/'
const FORM_API_ENDPOINT = 'https://www.####.com/wp-json/contact-form-7/v1/contact-forms/1217/feedback'
const captchaThreshhold = 0.5
exports.handler = async function(event, context) {
const eventBody = JSON.parse(event.body)
const captchaToken = eventBody.token
const stringFormData = eventBody.formData
let parsedFormData = JSON.parse(stringFormData);
console.log('>> parsedFOrmData ', parsedFormData) //logs a JSON object with correct key/value pairs
// logs:
// >> parsedFOrmData {
// 'your-name': 'Jon Doe',
// 'tel-725': '(555) 555-5555',
// 'your-email': 'jon#doe.com',
// 'your-subject': 'Suuuuubject',
// 'your-message': 'Meeeeesage!'
// }
let formData = new FormData();
for ( var key in parsedFormData ) {
formData.append(key, parsedFormData[key])
}
// I get values is not a function
for (var value of formData.values()) {
console.log('>> VALUE = ',value);
}
// I get entries is not a function
for (var pair of formData.entries()) {
console.log(pair[0]+ ', ' + pair[1]);
}
// (...)
axios.post(FORM_API_ENDPOINT, {formData}, {
headers: {
'Authorization': `Bearer ${res.data.token}`,
// 'Content-Type': 'multipart/form-data; charset="utf-8"', //do I need this?
}
})
.then( res => {
console.log('>> response came back from the Form endpoint : ',res)
})
// the res.data I get back form WordPress Contact Form 7 Plugin Endpoint:
data: {
into: '#',
status: 'validation_failed',
message: 'One or more fields have an error. Please check and try again.',
posted_data_hash: '',
invalid_fields: [ [Object], [Object], [Object], [Object] ]
}
//res.config data logs as this:
{"formData":{"_overheadLength":545,"_valueLength":54,"_valuesToMeasure":[],"writable":false,"readable":true,"dataSize":0,"maxDataSize":2097152,"pauseStreams":true,"_released":false,"_streams":["----------------------------611729353459041078880042\\r\\nContent-Disposition: form-data; name=\\"your-name\\"\\r\\n\\r\\n","Jon Doe",null,"----------------------------611729353459041078880042\\r\\nContent-Disposition: form-data; name=\\"tel-725\\"\\r\\n\\r\\n","(555) 555-5555",null,"----------------------------611729353459041078880042\\r\\nContent-Disposition: form-data; name=\\"your-email\\"\\r\\n\\r\\n","jon#doe.com",null,"----------------------------611729353459041078880042\\r\\nContent-Disposition: form-data; name=\\"your-subject\\"\\r\\n\\r\\n","Suuuuubject",null,"----------------------------611729353459041078880042\\r\\nContent-Disposition: form-data; name=\\"your-message\\"\\r\\n\\r\\n","Meeeeesage!",null],"_currentStream":null,"_insideLoop":false,"_pendingNext":false,"_boundary":"--------------------------611729353459041078880042"}}
If you know what the problem is.. Please tell me what I'm doing wrong! Thank you! :)
I solved the issue... it seems that the FormData headers need to be passed along with the data.. I randomly stumbled across the answer while messing around with Postman and found the answer buried in the Node.js code view.
For those of you who have the same issue.. see below:
axios.post(FORM_API_ENDPOINT, formData, {
headers: {
'Authorization': `Bearer ${res.data.token}`,
'Content-Type': 'multipart/form-data; charset="utf-8"',
...formData.getHeaders() // <--- THIS LINE HERE
}
})

Save images in S3 from React SPA with express backend

I have a React component where I ask the user to insert an image using react-dropze. On drop, I save the image into an image state.
Like this:
const handleOnDrop = (files) => {
setimage(files[0]);
}
Once I submit, I send a request to my back-end in order to get the URL with this function:
export const generateUploadURL = async () => {
const rawBytes = await randomBytes(16);
const imageName = rawBytes.toString('hex');
const params = ({
Bucket: process.env.S3_BUCKET_NAME,
Key: imageName,
ContentType: 'image/*',
Expires: 60
})
const uploadUrl = await s3.getSignedUrlPromise('putObject', params);
return uploadUrl;
}
I get the URL and finally execute a put into the s3 with the URL:
await axios.put(url, {
headers: {
"Content-Type": "multipart/form-data"
},
body: image
});
And then I save the data into my database but that's not important.
The thing is, after that, I can't render the image from the link I stored so I went into the link and encountered this:
{"headers":{"Content-Type":"multipart/form-data"},"body":{"path":"asdasdsadtest.jpg"}}
I tried setting the content-type to the imageType but that didn't work either. I have no clue on how I could make it work.
Why are you using the s3.getSignedUrlPromise('putObject ") api? Using s3.upload would allow you to send the file in one go and would make it much simpler in my opinion. See: https://stackabuse.com/uploading-files-to-aws-s3-with-node-js/ for an example of this solution
Solved it the following way:
url = await getS3Url(image);
await axios.put(url, image, {
headers: {
"Content-Type": image.type
}
});
Insted of placing it into the body, this worked.

How can I test file-upload with hapi?

I have this payload format in my hapi route that accepts only multipart/form-data data and the output is set as a stream:
payload: {
maxBytes: 1024,
output: 'stream',
parse: true,
allow: 'multipart/form-data',
}
I want to test that route and my payload is this:
const FD = new FormData();
FD.append('field1', 'value');
FD.append('field2', 'value');
The hapi inject method looks like this:
const res = await server.inject({
method,
url,
headers: {
...
'Content-Type': 'multipart/form-data; boundary=--SEPARATION--',
},
payload: FD,
});
I am getting
Invalid multipart payload format
I tried to set a stream using a Steam object too but it doesn't work. Also I tried to send a File object.
At this point I just want to send something to the route that will not result in an error. It's not necessary to be a FormData. Anything that will be accepted by the route is fine as long as I can add some custom fields to test it further.
Thanks in advance.
As far as I know, FormData doesn’t exist in node.js, so I assume you’re using the form-data module?
In that case, you need to ask form-data for the buffer and headers separately, like this:
const FormData = require('form-data');
const FD = new FormData();
FD.append('field1', 'value');
FD.append('field2', 'value');
const response = await server.inject({
method,
url,
headers: {
<your other headers>
...FD.getHeaders(),
},
payload: FD.getBuffer(),
});
If you want to test sending files, you also need to provide the filename property to append(…) for the binary data to be decoded correctly by the server:
const fileContent = <any Buffer>;
FD.append('form_file_property', fileContent, {filename: 'a testfile'});

Google Cloud functions call URL hosted on Google App Engine

I have a firebase database that I wish to create a cloud function that triggers when adding a child node to the parent node , which should call a url with the parameters of the child node added in the parent node.
The URL which would be called is a NodeJS Express app hosted in Google App Engine.
How do I do that, if it is even possible?
You can use the node.js request library to do so.
Since, inside your Cloud Function, you must return a Promise when performing asynchronous tasks, you will need to use an interface wrapper for request, like request-promise.
You could do something along these lines:
.....
var rp = require('request-promise');
.....
exports.yourCloudFucntion = functions.database.ref('/parent/{childId}')
.onCreate((snapshot, context) => {
// Grab the current value of what was written to the Realtime Database.
const createdData = snapshot.val();
var options = {
url: 'https://.......',
method: 'POST',
body: ....
json: true // Automatically stringifies the body to JSON
};
return rp(options);
});
If you want to pass parameters to the HTTP(S) service/endpoint you are calling, you can do it through the body of the request, like:
.....
const createdData = snapshot.val();
var options = {
url: 'https://.......',
method: 'POST',
body: {
some: createdData.someFieldName
},
json: true // Automatically stringifies the body to JSON
};
.....
or through some query string key-value pairs, like:
.....
const createdData = snapshot.val();
const queryStringObject = {
some: createdData.someFieldName,
another: createdData.anotherFieldName
};
var options = {
url: 'https://.......',
method: 'POST',
qs: queryStringObject
};
.....

Resources