Image upload from React to NodeJS, port connection refused - node.js

Hello Dear Community :)
I'm trying to code an image upload on my website, from React to Backend in NodeJS.
I have this error with this port connection.
This path http://localhost:5000/api/plants with post method works fine in PostMan (with uploading picture). The problem occurs when I want to upload to the backend server.
Here is the problem logged in the console
xhr.js:177 POST http://localhost:5000/api/plants
net::ERR_CONNECTION_REFUSED
Here is my code :
import React, { Component, useState } from "react";
import axios from 'axios';
class UploadImg extends Component {
state = {
image: null,
}
handleChange = event => {
this.setState({
image: event.target.files[0],
loaded: 0,
})
}
handleFileUpload = event => {
console.log('the new file upload is :', event.target.files[0]);
}
onClickHandler = (event) => {
const data = new FormData()
data.append('file', this.state.image)
axios.post('http://localhost:5000/api/plants', data)
.then(res => {
console.log(res)
})
.catch((error) => {
console.log(error)
})
event.preventDefault();
}
render() {
return (
<div>
<h2>New Thing</h2>
<form onSubmit={this.handleSubmit}>
<input type="file" onChange={this.handleFileUpload} />
<button onClick={this.onClickHandler} type="submit">Upload</button>
</form>
</div>
)
}
}
export default UploadImg

This link might help you: https://www.digitalocean.com/community/questions/why-can-i-call-api-port-from-react-app-using-ip-address-but-not-when-i-use-localhost
TL;DR: replace localhost in the axios request to whatever your machine's IP address is.

Related

How to send multipart-data video file from NextJS frontend to Express backend?

I am trying to enable a user to upload a video file and send it through my NextJS api to my Express backend (and store it in an S3 bucket, I don't have a need to save it on my server), but cannot figure out how to do it after days of searching. I understand that NextJS has a limitation where it cannot read multipart form data, but I don't understand how to strategically address this issue. I have seen packages like multer and formidable, but I am unsure how to use them (since they seem to be for the backend, and I am having trouble passing the file to my frontend API).
Since the video files can be big, I think I need to upload the video files to s3 directly from the frontend (using a multipart upload) and then send the AWS URL for the video to the backend. If this is the right approach, how do I do that?
Project setup: NextJS frontend running on port 3000 + Express backend server running on port 5000. Here is my code:
FileUpload.tsx (frontend)
...
<div>
<div>
{
previewURL != null ?
file.type.includes("video") ?
<video id="video" width="800" controls>
<source src={ previewURL } id="videoSrc" />
</video>
:
<audio id="audio" controls>
<source src={ previewURL } id="audioSrc" />
</audio>
: null
}
<form action="/api/uploadToAssemblyAi" method="post">
<label htmlFor="file">File</label>
<input
type="file"
id="file"
name="file"
onChange={ generatePreview }
/>
<button type="submit"> Upload </button>
<button type="reset" onChange={ clearFile }> Clear </button>
</form>
</div>
</div>
...
/api/uploadToAssemblyAi.tsx (frontend)
import type { NextApiRequest, NextApiResponse } from 'next'
import axios from "axios"
export const config = {
api: {
bodyParser: false
}
}
export async function uploadData(file: File) {
// Prep to send file to backend
const BACKEND_API_URL = process.env.BACKEND_URL
const assembly = axios.create({
baseURL: BACKEND_API_URL,
withCredentials: true,
});
// Add file to request
let formData = new FormData();
formData.append("file", file);
// Call backend
const { data } = await assembly.post(`${BACKEND_API_URL}/api/synthesize/transcribe}`, formData)
const transcriptionId = data.transcriptionId
return transcriptionId
}
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const file = req.body.file
// ^^^ This is not working, I cannot access the file from the form (this is for communication purposes, I know this isn't the right way to do it)
try {
const transcriptionId = await uploadData(file)
return res.status(201).redirect(307, `/calls/${transcriptionId}`)
} catch (err) {
console.log("Error: " + err)
return res.status(400).send( { msg: err })
}
}
uploadController.ts (backend)
...
// This is where I want to receive the file to upload to AWS
export async function transcribeController(req: Request, res: Response) {
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).send({ msg: 'No files were uploaded.' });
}
const file = req.files
const file = req.body
// ^^^ I'm not sure how to access the file on the backend since I cannot even send it from the frontend (this is for communication purposes, I know this isn't the right way to do it)
return
}
...
You can use FormData to send the request. This will be sent as a multipart/form-data request.
let formData = new FormData();
formData.append('file', file);
const response = await fetch('/api/uploadToAssemblyAi', {
method: 'POST',
body: formData,
});
You can also update your form element to specify that content type:
<form
action="/api/uploadToAssemblyAi"
method="post"
enctype="multipart/form-data"
>

Using promise, resolve and axios and get multiple same returns each time GET [duplicate]

This question already has answers here:
How to call loading function with React useEffect only once
(15 answers)
Closed 3 months ago.
I am currently learning nodejs and react, and I want to achieve data transmission between frontend and backend. During this, I found that every time I refresh the website, the console in the browser would print out the content several times.
Here is my frontend code for post, get data and display data result.
callAPI.js
import axios from 'axios'
const api = 'http://localhost:5000'
class callAPI{
getSomething(){
return new Promise((resolve)=>resolve(axios.get(`${api}`)))
}
sendSomething(body){
return new Promise((resolve)=>resolve(axios.post(`${api}/hello`,body)))
}
}
export default new callAPI()`
Page.js
import React, { useState } from 'react'
import callAPI from './callAPI';
export default function Page(){
const[content, setContent] = useState("")
const[greeting, setGreeting] = useState("")
function getContent(){
callAPI.getSomething().then(response=>{
console.log(response.data)
setContent(response.data)
})
}
function handleLB(){
callAPI.sendSomething({name:"Sam"})
.then((response)=>{
console.log(response.data)
setGreeting(response.data)
})
}
function handleCC(){
callAPI.sendSomething({name:"Mary"})
.then((response)=>{
console.log(response.data)
setGreeting(response.data)
})
}
getContent()
console.log(content)
return(
<>
<h1>{content}</h1>
<div>
<button onClick={handleLB}>Sam is comming</button>
<button onClick={handleCC}>Mary is comming</button>
</div>
<div>
<p>{greeting}</p>
</div>
</>
)
}
Here is my backend code
app.js
var express = require('express');
var cors = require('cors')
var app = express();
const greeting={"Sam":"Handsome boy","Mary":"Young and beautiful lady"}
var corsOptions={
credentiala:true,
origin:'http://localhost:3000',
optionsSuccessStatus:200
}
app.use(cors(corsOptions))
app.use(express.urlencoded({extended:true}));
app.use(express.json());
app.get('/',function(req, res) {
res.send('Knock knock, who\'s coming?')
})
app.post('/hello',function(req, res){
//console.log(req.body.name)
let grt = greeting[req.body.name]
res.send(grt)
})
app.listen(5000,function(){
console.log('App is listening on port 5000...')
})
And here is a picture of my browser console
In my understanding, each GET/POST should only have one return results. In this case, when I POST something, I only get one return results. But for GET, I get multiple. And I'm really curious why this would happen.
First of all axios return promise by itself so don't need to put again in Promises and call getContent using useEffect.
useEffect(() => {
getContent()
},[])
In dependency array you can have some dependency or leave it blank(so it will call the getContent only once time)

Fetch request not fetching backend object - nextjs and express

I have a Nextjs frontend trying to make a fetch request to my node and express backend but it's not happening for some reason. I'm trying to access this object in the backend: {"data": ["data1", "data2", "data3"]} but I'm not able to even fetch it. Here is my backend code:
const express = require('express')
const app = express()
app.get("/api", (req, res) => {
res.json({"data": ["data1", "data2", "data3"]})
})
app.listen(5000, () => { console.log("Server started on port 5000") })
Here is my next.js file trying to make this request:
import React, { Component, useEffect, useState } from 'react';
const Product = () => {
const [backendData, setBackendData] = useState([{}])
useEffect(() => {
fetch("/api").then(
response => response.json()
).then(
data => {
setBackendData(data)
}
)
}, [])
return (
<div>
{(typeof backendData.data === 'undefined') ? (
<p>Loading...</p>
) : (
backendData.data.map((data, i) => (
<p key={i}>{data}</p>
))
)}
</div>
);
}
export default Product
I've included this line in my package.json file "proxy": "http://localhost:5000", so it should be going to that link and when I search http://localhost:5000 in my browser, I get the object that I've written in the backend like this: {"data":["data1","data2","data3"]}.
When I click on Network when I hit inspect on the page, the fetch request doesn't show up either.
Does anyone know why I'm unable to fetch this object in nextjs?

ReactJS download file from Express Server

I'm trying to make my user able to download a file from our backend server. I've tried the solution from this question as well as the backend from this.
Sadly none of them worked. The download itself works through postman, but not in react.
Additional info: The Backend is running on the same machine but on port 3001 while the frontend is running on port 3000
I'm not sure if that helps, but the react frontend is connected to the backend via proxy in the package.json
"proxy": "http://localhost:3001",
The client side currently looks like this:
const download = require("downloadjs");
const handleDownload = async () => {
const res = await fetch("http://localhost:3001/download");
const blob = await res.blob();
download(blob, "test.pdf");
}
function App() {
return (
<div className="App">
<header className="App-header">
<button onClick={() => handleDownload().finally(() => console.log("Passed through the whole handleDownload Request"))}> </button>
</header>
</div>
);
}
while on the backend side I'm using this code as from the previous questions asked here on stackoverflow.
app.get('/getdoc', function (req, res) {
res.download(path.join(__dirname, 'files/test.pdf'), function (err) {
console.log(err);
});
});
This is the Code working through Postman, but it won't trigger a download in React.
The Error occurring in react looks like this:
App.js:8 GET http://localhost:3001/download/test.pdf net::ERR_CONNECTION_REFUSED
Uncaught (in promise) TypeError: Failed to fetch
So it seems the handling on frontend seems to be the problem, as it is not triggering the Save Dialog from the browser (Chrome).
Your request to postman will work because I assume you are hitting the correct endpoint which is '/getdoc' which will let you download the pdf via postman.
However, your fetch request does not seem to match the API endpoint that serves the pdf document. That is why your React Component will give you the error on download.
const handleDownload = async () => {
const res = await fetch("http://localhost:3001/download");
const blob = await res.blob();
download(blob, "test.pdf");
}
//the fetch call for "http://localhost:3001/download" will not hit '/getdoc'
app.get('/getdoc', function (req, res) {
res.download(path.join(__dirname, 'files/test.pdf'), function (err) {
console.log(err);
});
});
Here is how I implemented the pdf download.
//resume route... this route is hit when you make a GET request to /api/resume
const router = require('express').Router();
module.exports = router;
//when route is hit the resume is downloaded
//aka /api/resume
router.get('/', (req, res, next) => {
try {
const file = `${__dirname}/resume/resume.pdf`;
res.download(file);
console.log('here');
} catch (err) {
console.log(err);
}
});
//react component
import React from 'react';
import download from 'downloadjs';
const Resume = () => {
return (
<div>
<button
type="button"
onClick={async () => {
const res = await fetch('/api/resume');
const blob = await res.blob();
download(blob, 'test.pdf');
}}
>
Download
</button>
</div>
);
};
Try this:
const handleDownload = () => {
var reqObj = new XMLHttpRequest();
reqObj.open('GET','http://localhost:3001/download',true); // 'getpdf' is the URI to recongize your request at the server
reqObj.send();
reqObj.onreadystatechange = function() {
var resObj = this;
if(resObj.readyState == resObj.DONE) {
if (resObj.status != 200) {
console.log(200);
} else if (resObj.status == 200){
var resTxt = reqObj.responseText;
window.location.assign(resTxt); // Opens the pdf download prompt
}
}
}

Render Remote Component on Server Side Next.js

I am attempting to build a React component library which can be independently deployed from the apps which use it. I'm doing this by loading the components over the network, and then rendering them in a Next.js app. I know I can achieve this using react-umd-loader, but that only works client side because it relies on scriptjs. I was able to get this working using the vm npm package. This is what my page in Next.js looks like.
const Index = (props) => {
let sandbox = {'React': React, 'ReactDOM': ReactDOM, 'MyComponent': null, 'self': {}};
vm.runInNewContext(props.MyComponent, sandbox);
const MyComponent = sandbox.MyComponent.default;
return (<div><p>Hello from Next.js</p><MyComponent /></div>)
}
Index.getInitialProps = async function() {
const res = await fetch('http://localhost:3001/MyComponent.bundle.js')
const script = await res.text()
return { MyComponent: script }
}
MyComponent is a react component built with the following webpack.config.js
entry: {
MyComponent: "./src/components/MyComponent",
},
output: {
path: path.resolve(__dirname, 'build/static/js'),
filename: "[name].bundle.js",
libraryTarget: "umd",
library: "[name]",
umdNamedDefine: true,
globalObject: 'this'
},
This actually works fine, but, I want the component to fetch data and then display that data, which is not working.
class MyComponent extends Component {
constructor() {
super();
this.state = {data: {msg: 'data not loaded'}};
}
componentDidMount() {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(json => this.setState({data: json}))
.catch(err => console.log(err));
}
render() {
return (
<div style={{border: '1px solid black'}}>
<h1>My Component</h1>
This data was fetched from an API:
<pre>
{JSON.stringify(this.state.data)}
</pre>
</div>
);
}
}
I think the reason this is not working is because the fetch is asynchronous, and the page is rendered and returned to the client before the fetch completes. I tried using fetch-suspense but this did not work. I see Promise { <pending> } on the server console, so maybe the fetch promise just isn't completing?
Is it possible to make the server wait to respond until the fetch from the API has completed?
My full repo is at https://github.com/bernardwolff/ReactRemoteComponentSsr
Thanks!

Resources