Remix Run UploadHandler Using Data for WhatsApp API Media Upload - node.js

I am attempting to use a form in Remix to add a file and then upload that file to WhatsApp using their Cloud API Media Upload endpoint. Below is my initial code within the action. The current error I am receiving is message: '(#100) The parameter messaging_product is required.. I feel like this error may be misleading based off the form data I have appended with the "messaging_product".
export async function action({ request, params }: ActionArgs) {
const uploadHandler = unstable_composeUploadHandlers(
async ({ name, contentType, data, filename }) => {
const whatsAppPhoneId = process.env.WHATSAPP_PHONE_ID;
const whatsAppToken = process.env.WHATSAPP_ACCESS_TOKEN;
const dataArray1 = [];
for await (const x of data) {
dataArray1.push(x);
}
const file1 = new File(dataArray1, filename, { type: contentType });
const graphApiUrl = `https://graph.facebook.com/v15.0/${whatsAppPhoneId}/media`;
const formData = new FormData();
formData.append("file", file1);
formData.append("messaging_product", "whatsapp");
formData.append("type", contentType);
try {
const imageMediaResponse = await fetch(graphApiUrl, {
method: "POST",
headers: {
Authorization: `Bearer ${whatsAppToken}`,
"Content-Type": "multipart/form-data",
},
body: formData,
});
const imageMedia = await imageMediaResponse.json();
return imageMedia?.id;
} catch (error) {
console.error(error);
}
const whatsAppMediaId = await uploadWhatsAppImageMedia(
whatsAppPhoneId,
whatsAppToken,
data,
filename,
contentType
);
}
);
const formData = await unstable_parseMultipartFormData(
request,
uploadHandler
);
}

Related

How to file using formdata and axios in node js

This is my code:
async function uploadDocForPlagScan(params) {
try {
console.log(params);
const token = await getTokenForDocumentUpload();
const { data: arr } = await axios.get(
"https://kmsmediasvcstorage.blob.core.windows.net/knowledgesfqueryuat/6-P.pdf",
{ responseType: "arraybuffer" }
);
const apiKey = "idF******************";
const fileName = "WHNTMB.pdf";
const filePath = path.join(__dirname, "WHNTMB.pdf");
const fileContent = await fs.readFileSync(filePath);
const formData = new FormData();
formData.append("fileUpload", fileContent, fileName);
formData.append("language", "en");
const headers = {
"Content-Type": "multipart/form-data",
Authorization: `Bearer ${apiKey}`,
};
const response = await axios.post(
`https://api.plagscan.com/v3/documents?access_token=${token.data}`,
{ fileUpload: formData },
{ headers }
);
console.log(response.data);
} catch (error) {
p = error;
}
}
I tried to upload file in node js by making post call in https://api.plagscan.com/v3/documents?access_token=amdsfa

Send blob pdf file from #react-pdf/renderer via rest API to Nest-js server that use fileInterceptor

Im unable to send blob pdf file that comes from #react-pdf/render.
first I'm tring to convert that blob into a file using new File()
<BlobProvider
document={<Document />}
>
{({ blob, url, loading, error }) => {
buildPdfFile(blob);
return <div />;
}}
</BlobProvider>
const fileRef = useRef<File | null>(null);
const buildPdfFile = (blob: any) => {
const file = new File(
[blob],
`${get(resumeData, "ownerName", "")}_${get(
resumeData,
"ownerId",
""
)}_ficha_de_inscripciĆ³n.pdf`,
{
type: "application/pdf",
}
);
fileRef.current = file;
console.log(fileRef.current);
};
const handleOnSubmit = () => {
dispatch(sendPdfToServer(fileRef.current!));
};
once I got that file I'm tried to send it using formdata in a POST request with application/pdf as content-type to my nestjs app
const sendPdfToServer = (inscriptionPdf) => {
const jwt = getJWT();
const options = {
headers: new Headers({
"content-type": "application/pdf",
Authorization: `Bearer ${jwt}`,
}),
};
const formData = new FormData();
formData.append("file", inscriptionPdf, inscriptionPdf.name);
const path = `${url}`;
try {
const response = await fetch(path, {
...options,
method: "POST",
body: formData,
});
}
catch (e) {
console.log(e);
}
}
but in the endpoint I'm using, the file is never intercepted, it shows as undefined
#Post('sendMail')
#UseInterceptors(
FileInterceptor('file', {
storage: diskStorage({
destination: './uploads/emailsTemporalFiles',
filename: (req, file, cb) => {
console.log('file ->', file);
const fileName: string = path
.parse(file.originalname)
.name.replace(/\s/g, '');
const extension: string = path.parse(file.originalname).ext;
cb(null, `${fileName}${extension}`);
},
}),
}),
)
async sendMail(#Res() response, #UploadedFile() file) {
this.logger.log(` | sendMail`);
console.log(file); // it prints undefined
}

Sending form data server side

I am sending a formdata to an endpoint that requires the following data:
token_key,
customer_id,
folder_id,
document_id,
file
but I get an error when sending it, the steps I do are the following:
html file
submitBtn.addEventListener("click", function (e) {
if (is_signed) {
var dataUrl = canvas.toDataURL();
var image = dataURItoBlob(dataUrl);
var file = new File([image], 'firma.png', {
type: 'image/png'
});
var folder_id = location.search.slice(1).split("&")[0].split("=")[1]
var document_id = location.search.slice(1).split("&")[1].split("=")[1]
const formdata = new FormData();
formdata.append('document_id', parseInt(document_id));
formdata.append('folder_id', parseInt(folder_id));
formdata.append('file', file)
axios.post('/send-signature', formdata, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}, false)
Js file
router.post("/send-signature", (req, res) => {
const url_expa_signature = `${process.env.BASE_URL_EXPA}/upload-documents`
const document_id = req.body.document_id
const folder_id = req.body.folder_id
const file = req.files.file
const token_key = process.env.TOKEN_KEY
const customer_id = process.env.CUSTOMER_ID
const formdata = new FormData();
formdata.append('token_key', token_key);
formdata.append('customer_id', customer_id);
formdata.append('folder_id', folder_id);
formdata.append('document_id', document_id);
formdata.append('file', file);
axios({
method: 'post',
url: url_expa_signature,
data: formdata,
})
})
and the following error is
TypeError: source.on is not a function
any suggestion?
It was a problem with the endpoint that i consume, i solve it calling to suport and they fix the bug.

SvelteKit endpoint: converting from Node/Express

New to SvelteKit and working to adapt an endpoint from a Node/Express server to make it more generic so as to be able to take advantage of SvelteKit adapters. The endpoint downloads files stored in a database via node-postgresql.
My functional endpoint in Node/Express looks like this:
import stream from 'stream'
import db from '../utils/db'
export async function download(req, res) {
const _id = req.params.id
const sql = "SELECT _id, name, type, data FROM files WHERE _id = $1;"
const { rows } = await db.query(sql, [_id])
const file = rows[0]
const fileContents = Buffer.from(file.data, 'base64')
const readStream = new stream.PassThrough()
readStream.end(fileContents)
res.set('Content-disposition', `attachment; filename=${file.name}`)
res.set('Content-Type', file.type)
readStream.pipe(res)
}
Here's what I have for [filenum].json.ts in SvelteKit so far...
import stream from 'stream'
import db from '$lib/db'
export async function get({ params }): Promise<any> {
const { filenum } = params
const { rows } = await db.query('SELECT _id, name, type, data FROM files WHERE _id = $1;', [filenum])
if (rows) {
const file = rows[0]
const fileContents = Buffer.from(file.data, 'base64')
const readStream = new stream.PassThrough()
readStream.end(fileContents)
let body
readStream.pipe(body)
return {
headers: {
'Content-disposition': `attachment; filename=${file.name}`,
'Content-type': file.type
},
body
}
}
}
What is the correct way to do this with SvelteKit without creating a dependency on Node? Per SvelteKit's Endpoint docs,
We don't interact with the req/res objects you might be familiar with from Node's http module or frameworks like Express, because they're only available on certain platforms. Instead, SvelteKit translates the returned object into whatever's required by the platform you're deploying your app to.
UPDATE: The bug was fixed in SvelteKit. This is the updated code that works:
// src/routes/api/file/_file.controller.ts
import { query } from '../_db'
type GetFileResponse = (fileNumber: string) => Promise<{
headers: {
'Content-Disposition': string
'Content-Type': string
}
body: Uint8Array
status?: number
} | {
status: number
headers?: undefined
body?: undefined
}>
export const getFile: GetFileResponse = async (fileNumber: string) => {
const { rows } = await query(`SELECT _id, name, type, data FROM files WHERE _id = $1;`, [fileNumber])
if (rows) {
const file = rows[0]
return {
headers: {
'Content-Disposition': `attachment; filename="${file.name}"`,
'Content-Type': file.type
},
body: new Uint8Array(file.data)
}
} else return {
status: 404
}
}
and
// src/routes/api/file/[filenum].ts
import type { RequestHandler } from '#sveltejs/kit'
import { getFile } from './_file.controller'
export const get: RequestHandler = async ({ params }) => {
const { filenum } = params
const fileResponse = await getFile(filenum)
return fileResponse
}

Postman can upload file to a Node api. But Not with React

Redux Code
export const uploadImage = data => async dispatch => {
const config = {
headers: {
"Content-Type": "multipart/form-data"
}
};
try {
const res = await axios.post("/api/profile/upload", data, config);
// const res = await axios.post("/api/profile/upload", data, {
// headers: {
// "Content-Type": "multipart/form-data"
// }
// });
console.log(res);
dispatch({
type: AVATAR_UPLOAD,
payload: res.data
});
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, "danger")));
}
dispatch({
type: PROFILE_ERROR,
payload: { msg: err.response.statusText, status: err.response.status }
});
}
};
React Code
const data = new FormData();
data.append("file", avatar);
uploadImage(data);
I get bad request message, req.files is empty
I try to upload file with Postman same configuration,it seems api works but can't upload with react formdata.
Any idea would be appreciated. Thanks in advance
try doing this:
const formData = new FormData();
formData.append('file', file);
const res = await axios.post("/api/profile/upload", formData, config);

Resources