To complete Apar Adhikari's answer, I also realized what I needed to make this end to end process happen:
html form file input->onsubmit event->client post file to svr 1->file in svr 1->file in svr 2
was reading the file server-side as well, on server 1, using fs.createReadStream(filepath)
, where filepath
is the relative file path where I chose to upload my files to - on DISK for now, using Multer.
Only AFTER this file reading step, I appended fs.createReadStream(filepath)
as a value in the formData object he called form
, against the key my 3rd-party API located on server 2 will recognize.
So, basically, here is the journey that my file takes, once the onsubmit
event has fired client-side, and the file been posted from client-side to server 1
require("dotenv").config()
const express = require("express")
const bodyParser = require('body-parser')
const FormData = require('form-data') // svr-side require for multipart/form-data encoding
const path = require('path')
const fs = require('fs') // required to call fs.createReadStream() - see below
const cors = require('cors')
const multer = require('multer')
const axios = require('axios') // svr-side require for req to 3rd-party API
// Multer file storage options - I chose to store the file on DISK with the help of Multer, in a ./uploadFiles directory
const uploadedFilesFolderName = "uploadFiles"
const UPLOAD_DIR = `${__dirname}/${uploadedFilesFolderName}`
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, UPLOAD_DIR);
},
filename: function (req, file, cb) {
cb(null, `${file.originalname}`);
},
})
const upload = multer({ storage: storage });
const app = express()
const PORT = // port of your choice here
//const PORT = process.env.PORT // to change used PORT
const API_URL = "https://my.apiurl.com/"
app.use(express.static("public"))
app.use(express.json())
app.use(bodyParser.json())
app.use(cors())
app.use(express.static(UPLOAD_DIR)) // my ./uploadFiles dir
// serving index.html where the file input form is
app.get("/", function (request, response) {
response.sendFile(__dirname + "/public/views/index.html")
})
// my client->svr 1 post route
// in my HTML, the name of the file input field is 'fileInput'
// retrieved here with the help of upload.single('fileInput') arg
app.post('/upload-single-file', upload.single('fileInput'), async function (req, res, next) {
try {
// retrieving also text fields from the HTML form
// (eg a file description, an option chosen by user via a drop-down...)
const whateverTxt = req.body.whateverField // see multer doc for details on req.body
const fileFromClient = req.file // see multer doc for details on req.file object
//...
const apiToken = // here the result of a login request or sth authenticating into my 3rd-party API
// do whatever other prior async/await request with axios here
//...
// 1. Build the filepath where the file retrieved from client-side has "landed" (my ./uploadFiles dir)
let uploadedFilePath = `./${uploadedFilesFolderName}/${fileFromClient.originalname}`
// 2a. In this server 1, read the contents of the file to upload to server 2
// with fs.createReadStream(uploadedFilePath)
// 2b. Append fs.createReadStream(uploadedFilePath) into a new FormData object key-value pair
// with appropriate field for API on server 2
let form = new FormData();
form.append('fieldWhereToSendFileTo', fs.createReadStream(uploadedFilePath))
const API_POST_FILE_ENDPOINT = API_URL + `whatever/endpoint/to/post/to`
// using Apar Adhikari's answer
const fileResp = await axios.post(API_POST_FILE_ENDPOINT, form, {
headers: {
"id": apiToken,
"Content-Type": `multipart/form-data; boundary=${form._boundary}`
}
})
//console logging info received from svr 2 into svr 1
console.log(`POST/File to API - Status ${fileResp.status} - headers: ----${fileResp.headers}`)
// sending some response from svr 1 back to the client - including info from svr 2 axios response above (svr 2 -> svr 1 -> client)
res.json({ message: "successful file upload!",
data: req.file,
someOtherField: someOtherValue
postFileStatus: fileResp.status,
postFileHeaders: fileResp.headers,
url: `http://localhost:${PORT}/${req.file.originalname}`})
} catch (error) {
res.json({ message: "error - ", error })
}
})
// listen for requests :)
const listener = app.listen(PORT, function () {
console.log("Express SVR - Your app is listening on port " + listener.address().port)
})
Hope this explanation helps