Axios to Node (Express) GET Request - javascript

So using axios, I am attempting to make a request to my express server, here is my Axios request:
/* #flow */
import type {
Dispatch,
GetState,
ThunkAction,
Reducer,
} from '../../types';
export const USERS_INVALID = 'USERS_INVALID';
export const USERS_REQUESTING = 'USERS_REQUESTING';
export const USERS_FAILURE = 'USERS_FAILURE';
export const USERS_SUCCESS = 'USERS_SUCCESS';
export const API_URL = '/api/articleList';
// Export this for unit testing more easily
export const fetchUsers = (axios: any, URL: string = API_URL): ThunkAction =>
(dispatch: Dispatch) => {
dispatch({ type: USERS_REQUESTING });
return axios.get(URL)
.then((res) => {
dispatch({ type: USERS_SUCCESS, data: res.data });
})
.catch((err) => {
dispatch({ type: USERS_FAILURE, err });
});
};
// Preventing dobule fetching data
/* istanbul ignore next */
const shouldFetchUsers = (state: Reducer): boolean => {
// In development, we will allow action dispatching
// or your reducer hot reloading won't updated on the view
if (__DEV__) return true;
const userListFetch = state.userListFetch;
if (userListFetch.readyStatus === USERS_SUCCESS) return false; // Preventing double fetching data
return true;
};
/* istanbul ignore next */
export const fetchUsersIfNeeded = (): ThunkAction =>
(dispatch: Dispatch, getState: GetState, axios: any) => {
/* istanbul ignore next */
if (shouldFetchUsers(getState())) {
/* istanbul ignore next */
return dispatch(fetchUsers(axios));
}
/* istanbul ignore next */
return null;
};
and here is my code on the express server:
//GET ARTICLES
app.get('/api/articleList', (req, res) => {
console.log('hello');
});
It does not log "hello" and it displays no errors, I just think I'm missing something for the Axios to reach my server...
I had something similar working on another app but cannot seem to implement it here, I've searched online and cannot find a solution, any help or advice is appreciated - thank you in advance!
NOTE: the Axios request works fine when the "API_URL" variable is
set to a myjson url link, so I know my action works fine, I just feel
like I'm missing something for it to reach my server
EDIT: Please see my entire server.js:
/* #flow */
import path from 'path';
import morgan from 'morgan';
import express from 'express';
import compression from 'compression';
import helmet from 'helmet';
import hpp from 'hpp';
import favicon from 'serve-favicon';
import React from 'react';
import { renderToString, renderToStaticMarkup } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import { matchRoutes } from 'react-router-config';
import { Provider } from 'react-redux';
import chalk from 'chalk';
import createHistory from 'history/createMemoryHistory';
import configureStore from './redux/store';
import Html from './utils/Html';
import App from './containers/App';
import routes from './routes';
import { port, host } from './config';
const app = express();
// Using helmet to secure Express with various HTTP headers
app.use(helmet());
// Prevent HTTP parameter pollution.
app.use(hpp());
// Compress all requests
app.use(compression());
// Use morgan for http request debug (only show error)
app.use(morgan('dev', { skip: (req, res) => res.statusCode < 400 }));
app.use(favicon(path.join(process.cwd(), './build/public/favicon.ico')));
app.use(express.static(path.join(process.cwd(), './build/public')));
// Run express as webpack dev server
if (__DEV__) {
const webpack = require('webpack');
const webpackConfig = require('../tools/webpack/webpack.client.babel');
const compiler = webpack(webpackConfig);
app.use(require('webpack-dev-middleware')(compiler, {
publicPath: webpackConfig.output.publicPath,
hot: true,
noInfo: true,
stats: 'minimal',
}));
app.use(require('webpack-hot-middleware')(compiler));
}
// Register server-side rendering middleware
app.get('*', (req, res) => {
if (__DEV__) webpackIsomorphicTools.refresh();
const history = createHistory();
const store = configureStore(history);
const renderHtml = (store, htmlContent) => { // eslint-disable-line no-shadow
const html = renderToStaticMarkup(<Html store={store} htmlContent={htmlContent} />);
return `<!doctype html>${html}`;
};
// If __DISABLE_SSR__ = true, disable server side rendering
if (__DISABLE_SSR__) {
res.send(renderHtml(store));
return;
}
// Load data on server-side
const loadBranchData = () => {
const branch = matchRoutes(routes, req.url);
const promises = branch.map(({ route, match }) => {
// Dispatch the action(s) through the loadData method of "./routes.js"
if (route.loadData) return route.loadData(store.dispatch, match.params);
return Promise.resolve(null);
});
return Promise.all(promises);
};
// Send response after all the action(s) are dispathed
loadBranchData()
.then(() => {
// Setup React-Router server-side rendering
const routerContext = {};
const htmlContent = renderToString(
<Provider store={store}>
<StaticRouter location={req.url} context={routerContext}>
<App />
</StaticRouter>
</Provider>,
);
// Check if the render result contains a redirect, if so we need to set
// the specific status and redirect header and end the response
if (routerContext.url) {
res.status(301).setHeader('Location', routerContext.url);
res.end();
return;
}
// Checking is page is 404
const status = routerContext.status === '404' ? 404 : 200;
// Pass the route and initial state into html template
res.status(status).send(renderHtml(store, htmlContent));
})
.catch((err) => {
res.status(404).send('Not Found :(');
console.error(`==> 😭 Rendering routes error: ${err}`);
});
});
//----------------------------------------------------
//GET ARTICLES
app.get('/api/articleList', (req, res) => {
console.log('yoyoyo');
var indexLimit = parseInt(req.query.indexLimit, 10);
var articleId = req.query.articleId
var articles = [];
db.collection('articles')
.find()
.sort("dateAdded", -1)
.limit(indexLimit)
.toArray()
.then(result => {
articles = articles.concat(result);
}).then(() => {
res.send(articles);
}).catch(e => {
console.error(e);
});
});
//------------------------------------
//connect to mongo db
var db
const MongoClient = require('mongodb').MongoClient
MongoClient.connect('mongodb://##CHANGED###:test#ds123930.mlab.com:###/###', (err, database) => {
if (err) return console.log(err);
db = database
console.log('db connected');
})
if (port) {
app.listen(port, host, (err) => {
if (err) console.error(`==> 😭 OMG!!! ${err}`);
console.info(chalk.green(`==> 🌎 Listening at http://${host}:${port}`));
// Open Chrome
require('../tools/openBrowser').default(port);
});
} else {
console.error(chalk.red('==> 😭 OMG!!! No PORT environment variable has been specified'));
}

You will need to move your /api routes above:
app.get('*', (req, res) => {
...
}
Your call to /api/articleList is hitting that catch all route handler of '*' and responding to the request with the rendered page. When communicating with your api for data, you don't want a page render, you want the response from the api :)
Middleware is executed in order of appearance from top to bottom.

Related

failed to fetch (axios, nodejs, react)

My fetch takes too long until it fails
I tried chrome, edge and postman
other fetch requests from pixabay api are working great
I compared the code to other projects I've made and found nothing
I also added a proxy to "package.json" as suggested on some places and it didnt work
posting below parts of my code:
controller:
import axios from 'axios'
export const getAll = async () =>{
const response = await axios.get('https://pixabay.com/api/?key=25540812-faf2b76d586c1787d2dd02736')
.then(resp=>resp)
.catch(err=>console.log(err));
return response;
}
router:
import express from "express";
import * as homeController from '../controllers/home.controller.js'
const homeRouter = express.Router();
homeRouter.get('/all', homeController.getAll)
export default homeRouter
indexjs:
import express from "express"
import dotenv from "dotenv"
import homeRouter from './routers/home.router.js'
dotenv.config();
const PORT = 3000 //process.env.PORT
console.log(PORT);
const app = express();
app.use(express.json());
app.use(homeRouter)
app.listen(PORT, ()=>{console.log(`server is connected on port ${PORT}`)})
fetch:
const getAll = async()=>{
try {
const response = await fetch (`http://localhost:3000/all`)
console.log("hu");
if (!response.ok) {
throw new Error();
}
else{
console.log("ok");
}
const responseObj = await response.json();
console.log(responseObj);
}
catch (error) {
console.log(error);
}
}
useEffect(()=>{
getAll();
},[])
Posting the answer by #Jaromanda X for everyone to see:
"see this app.get('/', (req, res) => { ... where's you req and res ??? nowhere, that's where - hint: export const getAll = async (req, res) =>{"
Apparently EVERY controller made with express needs to send a response back (in the form of res.send)
Should be obvious but somehow I missed it
Thanks everyone!

Access ORM object from controller files (Mikro-Orm)

What is the proper way to pass the orm object to my controller functions. I want to be able to access the orm instance I created so that I can perform CRUD operations.
My server file:
import { MikroORM } from '#mikro-orm/core';
import { __prod__ } from './constants';
import microConfig from './mikro-orm.config';
import express from 'express';
import expense from './routes/expense';
const main = async () => {
const orm = await MikroORM.init(microConfig);
await orm.getMigrator().up();
const app = express();
// mount routes
app.use('/api/v1/expense', expense);
app.listen(4000, () => {
console.log('server started on localhost:4000');
});
};
console.log('==== STARTING ====');
main().catch(err => console.log(err));
My controller:
import { Request, Response } from 'express';
import { Expense } from 'src/entities/Expense';
// Get all expenses for a user
// GET /api/v1/expenses/:id
// Private
export function getExpense(request: Request, res: Response) {
res.send(`Get Expense: ${request.params.id}`);
}

next.js app works fine in local but returns 500 internal server error on production

the problem i'm having is basically my app works fine in local but in production anywhere that i've used server side rendering returns 500 internal server error. the other parts of my site which are called normally like in useEffect or componentDidMount work completely fine, like my dashboard or authorization process works without a problem, but anywhere that i have used ssr returns 500.
Below is some examples of how i have handled my ssr pages.
index page:
import React from 'react';
import HomePage from '../components/homePage/index'
import { Api, GuestHeaders } from '../components/config'
const Home = (props) => {
return <HomePage {...props} />
}
export async function getServerSideProps() {
const Response = await Api.get(`/v1/index`, { headers: GuestHeaders })
return {
props: {
Detail: Response.data,
}
}
}
export default Home
here is my Api component:
import axios from 'axios';
const GuestHeaders = {
'Authorization': "",
'content-type': 'application/json'
}
const Api = axios.create({
baseURL: 'baseUrl'
})
export { Api, GuestHeaders };
here is my server.js:
// server.js
const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
createServer((req, res) => {
// Be sure to pass `true` as the second argument to `url.parse`.
// This tells it to parse the query portion of the URL.
const parsedUrl = parse(req.url, true)
const { pathname, query } = parsedUrl
}).listen(3000, (err) => {
if (err) throw err
console.log('> Ready on http://localhost:3000')
})
})
and my next.config.js:
module.exports = {
basePath: '',
trailingSlash: false,
}

Next.js grpc-node usage

I use gRPC but I have a problem initializing the service in Next.js app.
Goal: Create client service only once in app and use it in getServerSideProps (app doesn't use client-side routing).
For example, we have a service generated with grpc-tools (only available on SSR) and then I just want to initialize it somewhere. At first I thought it can be realized in a custom server.js:
const { credentials } = require('#grpc/grpc-js');
const express = require("express");
const next = require("next");
const { MyserviceClient } = require('./gen/myservice_grpc_pb');
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
// Init & Export
exports.myService = new MyserviceClient(
'http://localhost:3000',
credentials.createInsecure(),
);
(async () => {
await app.prepare();
const server = express();
server.get("*", (req, res) => handle(req, res));
server.listen(process.env.PORT, () => {
console.log(`Listening at http://localhost:${process.env.PORT}`);
});
})();
And then use it on the homepage, for example:
import React from 'react';
const { GetSmthRequest } = require('../gen/myservice_pb');
const { myService } = require('../server.js');
const IndexPage = () => (
<div>
<span>My HomePage</span>
</div>
)
const getServerSideProps = async () => {
const request = new GetSmthRequest();
request.setSomeStuff('random');
myService.getStmh(GetSmthRequest, (err, res) => {
//...
})
return {
props: {
}
}
}
export default IndexPage;
But for some reason it's not possible to initialize the client service in the server.js.
Also I tried doing it with next.config.js:
const { credentials } = require('#grpc/grpc-js');
const { MyserviceClient } = require('./gen/myservice_grpc_pb');
module.exports = {
serverRuntimeConfig: {
myService: new MyserviceClient(
'http://localhost:3000',
credentials.createInsecure(),
),
},
};
This solution works, so I can use the service through serverRuntimeConfig, thereby initializing it only once in the entire application, but when I make a request somewhere using getServerSideProps, I get an error:
Request message serialization failure: Expected argument of type ...
Error explanation: (https://stackoverflow.com/a/50845069/9464680)
That error message indicates that message serialization
(transformation of the message object passed to gRPC into binary data)
failed. This generally happens because the message object doesn't
match the expected message type or is otherwise invalid
Does anyone know why I am getting this error?
It's also interesting to see some examples of using Next.js with grpc-node.
For such a case you can use Node.js global

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.

Categories