Next.js with Express Backend - javascript

I have a next.js application that runs with an express server. Everything was fine until the fetch. When I send from front-end to back-end post request, it works fine. And also when I try to fetch some data from another server it works fine. But whenever I want to fetch data from my server(same server as next app), it does not fetch. When I go to the page through the client(routes) it fetches everything, when I refresh and try (server side) does not work... When I console log the data inside getInitialProps it shows on the terminal(server). The error occurs only when I try to fetch something from my server.
Here is my server :
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
server.use(bodyparser.json());
server.use(cors());
server.use("/api", userRoutes);
server.get("/service/:slug", (req, res) => {
return app.render(req, res, "/service", { slug: req.params.slug });
});
server.get("*", (req, res) => {
return handle(req, res);
});
server.listen(port, err => {
if (err) throw err;
console.log(`> Ready on http://localhost:${port}`);
});
});
And this is service page:
import fetch from "isomorphic-fetch";
import Layout from "../components/layout";
const Service = ({ data }) => {
console.log(data,'ins');
return (
<Layout>
<div style={{ padding: "100px" }} className="componentDiv">
<p>xxx</p>
{/* <p>{json.longDesc}</p>
<img src={json.img} alt="" /> */}
</div>
</Layout>
);
};
Service.getInitialProps = async ({ query }) => {
const response = await fetch(
`http://localhost:3000/api/service/${query.slug}`
);
const jsonv = await response.json();
console.log(jsonv);
return { data: jsonv.data };
};
export default Service;
Update!
I used axios instead isomorphic fetch and problem solved.

Related

Integrate Nodejs Backend with React Frontend App

I am building an app that uses node.js for backend and react for frontend. In the backend, i have 2 functions that implement a post request.
In my react function:
I want to show a spinner while waiting for the response data from the API request.
For the triggerGrading function which only returns ok if successful, I want to be able to return a custom message in the frontend.
Here are my functions, and they work fine on postman. However, I am experimenting with NodeJS and React and want to know if there's any further logic I need to add to these backend functions to be able to accurately implement the spinner and a custom message return in the UI?
grading.js
const BASE_URL = htttp://localhost:8080
const postSubject = async (req, res, next) => {
const headers = {
"Score-API-Version": "v2",
"Content-type": "application/json",
};
const body = { name: 'Adam Lawrence' };
try {
const resp = await axios.post(`${BASE_URL}/subject`, body, { headers });
const response = resp.data;
res.send(response);
} catch (err) {
if (err.response) {
res.status(err.response.status).send(err.response.data);
} else if (err.request) {
res.send(err.request);
}
next(err);
}
};
const triggerGrading = async (req, res, next) => {
const { id } = req.params;
const headers = {
"Content-type": "application/json",
"Score-API-Version": "v2",
};
try {
const resp = await axios.post(`${BASE_URL}/start/${id}`, { headers });
const response = resp.data;
res.send(response);
} catch (err) {
if (err.response) {
res.status(err.response.status).send(err.response.data);
} else if (err.request) {
res.send(err.request);
}
next(err);
}
};
server.js
const express = require("express");
const flows = require("./grading.js");
const cors = require("cors");
const app = express();
app.use(cors());
const PORT = 5050;
app.use(express.json());
app.listen(PORT, () => {
console.log(`Running this application on the PORT ${PORT}`);
});
app.post("/subject", grading.postSubject);
React query is very easy comfy, but if you just want to explore a little bit on your own you can play with this example in codepen.
In order to show a spinner while the request is being made you can use useState:
const handleClickSpin = async()=>{
setIsLoading(true)
await postSubject()
setIsLoading(false)
}
and then conditionally show the spinner.
For the second part of your question, I assumed you didn't want to send the custom message from your sever, so I just added another flag with conditional rendering.

Cookie not showing up in browsers development tool application?

I am working on a web app project and for which i need to authenticate the user for some protected routes so i am using jwt tokens for this need.
Technologies used in project :-
frontend --> react
backend --> node, express
Node JS backend code.
const express = require('express');
const app = express();
const ProductModel = require('../Schemas/productSchema')
const product = ProductModel;
app.get('/', (req, res) => {
try {
product.find(function(err, data){
if(data){
res.cookie("test", "test1");
res.send(data);
}
else{
res.json({message : err});
}
})
} catch (error) {
res.json({message : error});
}
})
React frontend code.
here in this frontend code i am making a get request to the server using fetch
useEffect(() => {
async function fetchData(){
await fetch('http://localhost:5000/products')
.then(res => res.json())
.then(data =>{
// setProducts(data.data);
})
.catch(err => console.log(err))
}
fetchData();
}, [])
In the nodejs code i am sending cookie to the browser and for good the cookie is getting shown in the chrome devtool network
But cookie is not getting shown up in the browser->devtool->application->cookies
I don't know why this happening please submit the solutions with explanation.
First, I guess that u need to import the cookie parser
const cookieParser = require('cookie-parser')
app.use(cookieParser());
this lets you use the cookieParser in your application
And finally u can use it :
res.cookie(`...`);

Express not rendering my React Front End?

I have two repos for the Front End and Back End portions of my project.
The Front End is a simple create-react-app project that hits my Express Back End and received responses from API calls.
I ran npm run build in my Front End project and moved that build folder to the root of my express backend repo.
However, when I try to reach the root page (i.e. localhost:3001), for some reason the response only returns the static html from index.html and doesn't actually render anything.
But if I go to something that has a path like localhost:3001/pokedex/1 then at least I see a correct response coming from the API.
I have a feeling that there is something wrong with the way I'm declaring my paths.
Here is the code on the Front End that is reaching out to the Back End:
import axios from 'axios'
const baseUrl = '/'
const getAll = () => {
const request = axios.get(baseUrl)
return request.then(response => response.data)
}
const getPkm = (id) => {
const request = axios.get(`${baseUrl}pokedex/${id}`)
return request.then(response => response.data)
}
export default { getAll, getPkm }
This is my Express Back End entry index.js:
const express = require('express')
const app = express()
const cors = require('cors')
const axios = require('axios')
//Middleware
app.use(cors())
app.use(express.json())
app.use(express.static('build'))
const unknownEndpoint = (request, response) => {
response.status(404).send({ error: 'unknown endpoint' })
}
let fullPkmList = require('./fullPkmList.json')
function ignoreFavicon(req, res, next) {
if (req.originalUrl.includes('favicon.ico')) {
res.status(204).end()
}
next();
}
app.get('/', (req, res) => {
axios.get(`https://pokeapi.co/api/v2/pokemon/?limit=100`)
.then((list) => res.json(list.data.results))
})
app.get('/pokedex/:id', (request, response) => {
const id = Number(request.params.id)
const pokemon = fullPkmList[id - 1]
if (pokemon) {
axios.all([
axios.get(`https://pokeapi.co/api/v2/pokemon/${id}`),
axios.get(`https://pokeapi.co/api/v2/pokemon-species/${id}`)
])
.then(axios.spread((pokemonResponse, speciesReponse) => {
let pkmResponse = pokemonResponse.data
let speciesResponse = speciesReponse.data
response.json({pkm: pkmResponse, species: speciesResponse })
}))
} else {
response.status(404).end()
}
})
app.use(unknownEndpoint)
const PORT = process.env.PORT || 3001
app.listen(PORT, () => {
console.log(`this is a test ${PORT}`)
})
Code for the Front End: https://github.com/rohithpalagiri/pocketdex
Code for the Back End: https://github.com/rohithpalagiri/pocketdex-backend
To see the issue, you only need to run the backend. I console log the response and in that, you will see the index.html file markup being returned. My goal is to have all of the paths relative so that the root url doesn't really matter. I think that is the part I'm getting stuck on.
I'd appreciate any help!

React JS & Axios Render after getting response data from POST request

How would I go about rendering a component after an axios POST request? I want to load a new component after the success response has been received from Stripe. I am trying to update the state of my component by adding a setState after receiving the response and load a simple div if the state has any values. The issue I am having is that component is not re-rendering when I use the setState.
Below is how I have a stripe component setup and the express server:
import StripeCheckout from 'react-stripe-checkout';
import axios from 'axios';
import './stripe-button.styles.scss';
import { createStructuredSelector } from 'reselect';
import { selectCurrentUser } from '../../redux/user/user.selectors';
import { setCurrentUser } from '../../redux/user/user.actions';
class StripeCheckoutButton extends React.Component {
constructor(props) {
super(props);
this.state = {
cardListBacklog: []
};
}
onToken = token => {
console.log(token);
const { cartItems, price } = this.props;
const priceForStripe = price * 100;
const orderSummary = cartItems.reduce(
(cartItemAll, cartItem) =>
(cartItemAll += cartItem.name + cartItem.quantity),
''
);
axios({
url: 'payment',
method: 'post',
data: {
amount: priceForStripe,
order: orderSummary,
token
}
})
.then(response => {
alert(
`Payment successful, ${response.data.success.billing_details.name}; please check your email for your receipt.`
);
this.setState({cardListBacklog: response.data});
})
.catch(error => {
console.log('Payment error: ', JSON.parse(error));
alert('There was an issue with your payment. Please try again!');
});
};
render() {
const publishableKey = 'pk_test_gxxxxxxxxxxxxxxxxxxxxxxxxxxx';
const { price } = this.props;
const priceForStripe = price * 100;
return (
this.state.cardListBacklog.length
?
<div>Payment Successful</div>
:
<StripeCheckout
label="Pay Now"
name="Ltd."
billingAddress
shippingAddress
image="https://i.imgur.com/vWgUzv.png"
description={`Your total is $${price} USD`}
amount={priceForStripe}
panelLabel="Pay Now"
token={this.onToken}
stripeKey={publishableKey}
label="Pay with 💳"
/>
);
}
}
export default StripeCheckoutButton;
Here is my Server.js:
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const path = require('path');
if (process.env.NODE_ENV !== 'production') require('dotenv').config();
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const app = express();
const port = process.env.PORT || 5000;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());
if (process.env.NODE_ENV === 'production') {
app.use(express.static(path.join(__dirname, 'client/build')));
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
});
}
app.listen(port, error => {
if (error) throw error;
console.log('Server running on port: ' + port);
});
app.post('/payment', (req, res) => {
const body = {
source: req.body.token.id,
amount: req.body.amount,
receipt_email: req.body.token.email,
description: req.body.order,
currency: 'usd'
};
stripe.charges.create(body, (stripeErr, stripeRes) => {
if (stripeErr) {
res.status(500).send({ error: stripeErr });
} else {
res.status(200).send({ success: stripeRes });
}
});
});
this.state.cardListBacklog.length
This is the issue. Its giving 0 before update, and undefined after its updated. Console log and check if its true.
this.state = {
cardListBacklog: false
};
and
this.setState({cardListBacklog: true});
should do the trick.
I guess, you expects stripeRes in the state, but you are receiving an object
{success: stripeRes} instead.
You response with an object from the server here
res.status(200).send({ success: stripeRes });
But on the client side in the state you expect the array, not an object.
this.state.cardListBacklog.length
Object doesn't have length property by default.
You should check something else on the client. Maybe you should update state
on success response like
this.setState({cardListBacklog: response.data.success });
This is not super cool, but should give you an idea that client side and server side expect different things.
You should rethink your API.
The idea to use flag of successful response here (https://stackoverflow.com/a/59011695/10559239) makes sense to you, if you doesn't want to use response data in near future. Good as a first step.
But the main problem, as I can see is inconsistency between server and client.

How To Implement React hook Socketio in Next.js

I have tried to find a way from Google but the results can remain the same
 http://localhost:8000/socket.io/?EIO=3&transport=polling&t=MnHYrvR
i try this wan medium try other ways, the results remain the same
and for the front end I have tried, socket io inside the hook component and outside the scope, the results remain the same
http://localhost:8000/socket.io/?EIO=3&transport=polling&t=MnHYrvR
this is my code from server:
app.prepare().then(() => {
const server = express();
const setServer = require('http').Server(server);
const io = require('socket.io')(setServer)
server.use(bodyParser.json());
server.use(cookieParser());
io.on('connection', socket => {
console.log('socket', socket);
socket.emit('now', {
message: 'zeit'
})
})
server.use(routers)
server.get('*', (req, res) => {
return handle(req, res);
});
server.use( (err, req, res, next) => {
console.log(err)
if(err.name === 'Error'){
res.status(401).send({
title: 'error',
detail: 'Unauthorized Access!'
})
}
})
server.listen(port, err => {
if (err) throw err;
console.log(`> Ready on http://heroku:${port}`)
})
})
.catch(ex => {
console.error(ex.stack);
process.exit(1);
});
from front end:
//at the top of function
const io = require('socket.io-client');
const socket = io.connect('http://localhost:8000');
console.log('socket', socket);
//in use effect
useEffect(() =>{
socket.on('now', message => {
console.log('message', meesage);
})
})
Please help
Although I am not using Next.js, I have a similar setup with Express.js that might help you with your problem...
On my Node.js side I have the following setup:
const app = require('express')()
const server = require('http').createServer(app)
const io = require('socket.io')(server)
// ...
io.sockets.on('connection', () => {
console.log(`Client with ID of ${socket.id} connected!`)
io.sockets.emit('SOME_EVENT', 'HelloWorld')
})
Then, my frontend with React looks like this:
import React from 'react'
import io from 'socket.io-client'
function useSocket(url) {
const [socket, setSocket] = useState(null)
useEffect(() => {
const socketIo = io(url)
setSocket(socketIo)
function cleanup() {
socketIo.disconnect()
}
return cleanup
// should only run once and not on every re-render,
// so pass an empty array
}, [])
return socket
}
function App() {
const socket = useSocket('http://127.0.0.1:9080')
useEffect(() => {
function handleEvent(payload) {
console.log(payload)
// HelloWorld
}
if (socket) {
socket.on('SOME_EVENT', handleEvent)
}
}, [socket])
return (...)
}
Also, one common error that I am seeing when working with socket.io is the following:
Cross-Origin Request Blocked: The Same Origin Policy disallows
reading the remote resource at
http://127.0.0.1:9080/socket.io/?EIO=3&transport=polling&t=MnH-W4S.
(Reason: CORS request did not succeed).
This is due an incorrect URL that's provided as a parameter in the socket manager creation process:
const socket = io('http://localhost');
So just double check that the address you're providing is correct. If you're serving your application on now and accessing it through a now.sh URL, but providing http://localhost as your URL parameter, then it won't work.
(I realise that this is an old/stale question, but in the spirit of "The Wisdom of the Ancients".)
I came across this question because I had the exact same problem. I realised that I was using the wrong server to listen with. Instead of Express, you should use the HTTP module.
const setServer = require('http').Server(server);
const io = require('socket.io')(setServer)
So, this part...
server.listen(port, err => {
if (err) throw err;
console.log(`> Ready on http://heroku:${port}`)
})
...should become:
setServer.listen(port, err => {
if (err) throw err;
console.log(`> Ready on http://heroku:${port}`)
})

Categories