Dynamic GatsbyJS + Node Express deployment - node.js

I have a GatsbyJS app to which I added a dynamic side, starting with a contact form using Axios which on POST calls the Express server and sends an email.
Everything is now working locally, but I am having trouble moving to my provider as I am new to backend technology.
Locally, I followed https://www.gatsbyjs.org/docs/client-only-routes-and-user-authentication/ and added the server as a proxy in the package configuration. My host is using cPanel which allows configuring a NodeJS app, which I tried and setup the app but I cannot make it work properly with the front
gatsby-node.js
exports.onCreatePage = async ({ page, actions }) => {
const { createPage } = actions
// Only update the `/app` page.
if (page.path.match(/^\/app/)) {
// page.matchPath is a special key that's used for matching pages
// with corresponding routes only on the client.
page.matchPath = "/app/*"
// Update the page.
createPage(page)
}
}
ContactForm.js
const handleSubmit = e => {
e.preventDefault()
axios({
method: "POST",
url: "http://websiteaddress.com/post",
data: { name: name, email: email, message: message },
}).then (...)
app.js
const Router = () => {
return (
<MyRouter basepath="/more">
<ContactForm path="/contact" />
</MyRouter>
)
}
server.js is basically using nodemailer and working fine on localhost
My current online Node + static files uploaded to the server render only the static part (the form is not rendered). The Node app is running
How to adapt the configuration (for example the "proxy": "http://localhost:3000" which worked locally) to make it behave on the host as it should?

Related

Sending data from backend to React frontend via express - no ejs

I currently have 2 directories in my project, one for backend using express/axios and one for my React frontend. I have a discord authentication page which correctly authenticates and saves a user to my SQL database and express automatically redirects and sends the user information to an html page.
The problem is when I go to redirect the user after authenticating. I want to redirect them back to my React web application and also send the user information to the frontend. I cannot figure out how to do this without using ejs and other third-party applications.
This is my backend code and I want to use res.send(), res.redirect() etc... to be able to give the route which my react page is currently running (localhost:3000) the required data.
const { code } = req.query;
if (code) {
try {
const { data: credentials } = await exchangeAccessCodeForCredentials({
client_id: ID,
client_secret: SECRET,
grant_type: "authorization_code",
code: code.toString(),
redirect_uri: REDIRECT_URL,
});
const { data: user } = await getDiscordUserDetails(credentials.access_token);
const newUser = await createUser(buildUser(user, credentials));
res.setHeader("Auth", newUser.discordId);
res.redirect("http://localhost:3000");
} catch (err) {
console.log(err);
res.sendStatus(400);
}
}
}
I've also tried to retrieve that data from the headers, but the custom headers I set never show up when I log them...
async function trying() {
var req = new XMLHttpRequest();
req.open("GET", document.location, false);
req.send(null);
var headers = req.getAllResponseHeaders().toLowerCase();
alert(headers);
}
Please let me know if there is a way to easily send data to the frontend using only express and React. Thank you
What you need to do, is send all the information of the user to your react application, and handle of the redirection there.
So you have two scenarios:
The authentication is succesful, so you return the user information from your backend, and your React app should redirect to the other page.
The authentication failed, so your return an error or a 403 status code, and your React app should show the error there.

Formdata not being sent to database from browsers on mobile phone though it's working on desktop (frontend deployed on netlify and backend on heroku)

I deployed my frontend application on netlify and backend on heroku. When I'm using the desktop PC, the formdata is being sent to the database, all the functionality works fine. But, when I am trying to do the same from Chrome browser or other browsers on my mobile phone, the data is not being sent.
The following is the code on frontend:
await axios.post(
"https://tea-website-backend.herokuapp.com/api/v1/contact-form",
{
name,
email,
msg,
}
);
The backend respective code in app.js:
app.use("/api/v1/contact-form", submitFormRouter);
The controller functionality is:
const Contact = require("../models/Contact");
const { StatusCodes } = require("http-status-codes");
const submitForm = async (req, res) => {
const { name, email, message } = req.body;
const contactForm = await Contact.create({ ...req.body });
res.status(StatusCodes.OK).json("Successful");
};
module.exports = {
submitForm,
};
I tried with fetch too but the data is not being sent from mobile browsers (chrome and others, iphone one) though the functionality works from all desktop browsers:
await fetch(
"https://tea-website-backend.herokuapp.com/api/v1/contact-form",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name,
email,
msg,
}),
}
)
Would appreciate some suggestions.
Oh! I finally troubleshooted the silly bug! My Schema model wasn't accepting the formdata as the values I was trying to send were not satisfying the built-in validators. As I was testing the functionality, I didn't set up any validation on the frontend then- so couldn't figure out what exactly was going wrong. Anyways, it was about a day into sorting out this bug!

Why does my Next.js SSR api call Error: The default export is not a React Component in page:"/api/twilio" at Object.renderToHTML & how do I make work?

I have a Next.js application that has React components in the pages directory that render as expected. The application was built for a rails backend api and is using that backend every day properly. I am trying to add a twilio video chat to the app. I created an /api directory as instructed in all documentations. When I attempt to make a call to this api for literally a mock example to test the api I get the error in the terminal Error: The default export is not a React Component in page: "/api/twilio" at Object.renderToHTML (/home/application_in_question/node_modules/next-server/dist/server/render.js:117:19)
and I also get Failed to load resource: the server responded with a status of 500 (Internal Server Error) in the browser. I was not part of the team that built this application so I am unsure of why I cannot add this Next.js api. The api is the selling point of Next and it is supposedly built into the framework.
I get this error is I just put the route in the address bar of the browser but I also get it from a file api call.
pages/twilio/index.js
const handleFetchPosts = async () => {
debugger
const tokenResponse = await fetch("/api/twilio");
debugger
const tokenData = await tokenResponse.json();
debugger
setToken(tokenData);
};
section of package.json
"next": "^8.1.0",
"next-auth": "^1.8.5",
"next-compose-plugins": "^2.2.0",
"next-redux-wrapper": "^2.0.0",
"next-routes": "^1.4.2",
"next-seo": "^1.11.2",
"node-sass": "^4.12.0",
pages/api/twilio/index.js
console.log("running api")
const handler = (req, res) => {
return res.json({ hello: 'world!' });
};
export default handler;
next.config.js
const { withPlugins, optional } = require('next-compose-plugins')
// eslint-disable-next-line import/no-extraneous-dependencies
const { PHASE_PRODUCTION_BUILD } = require('next-server/constants')
const sass = require('#zeit/next-sass')
const { requireEnvVar } = require('./lib/utils')
Custom Next.js Configuration
#see https://nextjs.org/docs#custom-configuration
const nextConfig = {
Runtime configuration
#see https://nextjs.org/docs#exposing-configuration-to-the-server--client-side
publicRuntimeConfig: {
// Will be available on both server and client
apiUrl: requireEnvVar('API_SERVER'),
googleApiKey: requireEnvVar('GOOGLE_API_KEY'),
stripeApiKey: requireEnvVar('STRIPE_PUBLISHABLE_KEY'),
instantPayFee: requireEnvVar('INSTANT_PAY_FEE'),
},
Disable file-system routing
#see https://nextjs.org/docs#disabling-file-system-routing
**useFileSystemPublicRoutes: true,**
Custom webpack config
#see https://nextjs.org/docs#customizing-webpack-config
webpack(config, { webpack }) {
Only load specific locales for moment.js
#see https://stackoverflow.com/a/25426019/956688
config.plugins.push(
new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /en/)
)
return config
},
}
Load multiple plugins with next-compose-plugins
#see https://github.com/cyrilwanner/next-compose-plugins
module.exports = withPlugins(
[
[sass],
Analyzing the webpack bundle
#see https://github.com/zeit/next-plugins/tree/master/packages/next-bundle-analyzer
Load #zeit/next-bundle-analyzer as an optional plugin only during production build
#see https://github.com/cyrilwanner/next-compose-plugins#optional-plugins
#see https://github.com/cyrilwanner/next-compose-plugins#phases-array
[
// eslint-disable-next-line global-require,import/no-extraneous-dependencies
optional(() => require('#zeit/next-bundle-analyzer')),
{
analyzeServer: ['server', 'both'].includes(process.env.BUNDLE_ANALYZE),
analyzeBrowser: ['browser', 'both'].includes(
process.env.BUNDLE_ANALYZE
),
**bundleAnalyzerConfig: {
server: {
analyzerMode: 'static',
reportFilename: '../../bundles/server.html',
},
browser: {
analyzerMode: 'static',
reportFilename: '../bundles/client.html',
},
}**,
},
[PHASE_PRODUCTION_BUILD],
],
],
nextConfig
)`
As you can see above the team before me had useFileSystemPublicRoutes set to false. I have made this true.
When I attempt to fetch the api in the react page or use a get request in the browser for the api/index.js file I created with the code
`
console.log("running api")
const handler = (req, res) => {
return res.json({ hello: 'world!' });
};
export default handler;`
This gives the error above. This is a very simple example that I have seen work in numerous resources online so I do not understand why this is happening.
How can I get this api to work???
** I added the ** in an attempt to highlight the parts I think could help. I already set useFileSystemPublicRoutes to true.
You can read in the comment thread Next#8 was before API routes were added to the framework. I ended up using a workaround where I used the rails backend server. Next version 9+ has api routes where any file in a pages/api directory is treated as a server backend api file. Next 8 was treating pages/api/file as a front-end webpage file looking for react.

How to implement clean Next.js URL in graphql-yoga

I am creating a GraphQL app using Next.js for server side rendering. As you might know, there is a recommended way to implement clean URL using Express. I am trying to achieve the same using graphql-yoga but it's not working.
I have tried server.express.get('/route', ...) and server.get('/route', ...) but nothing is working. In the documentation they have given server.express.get(server.options.endpoint, handler()) but it's not working for me.
Has anyone ever implemented clean Next.js URL in a GraphQL Yoga server, and how did you achieve it? Below is how I am creating the server.
function createServer() {
return new GraphQLServer({
typeDefs: "src/schema.graphql",
resolvers: {
Mutation,
Query
},
context: req => ({ ...req, db })
});
}
const server = createServer();
server.express.post('/product/name', (req,res,next) => {
//this is where i want to implement next clean url
//but it's not working
console.log('Am never reached..');
next();
})
With the new versions of Next.js, creating clean URL is straightforward.
Create a parameterised page (e.g. pages/post/[pid].js):
import { useRouter } from 'next/router'
const Post = () => {
const router = useRouter()
const { pid } = router.query
return <p>Post: {pid}</p>
}
export default Post
More info in the Next.js documentation regarding dynamic routes.
You can then link to it and show the desired URL:
<Link href="/post/[pid]" as="/post/abc">
<a>First Post</a>
</Link>

How to manage authentication of a user through a vue router and a server-provided JWT token?

I am building a web app using vue/webpack for the front end and node.js/express on back end. The node.js back end is exposing REST APIs that are used by the front end to login, logout and other CRUD-like operations.
On server side, the login REST API is setting a JWT token and redirects to the vue application home path.
On front end side, the vue components access (including home) is guarded by the beforeEach method of the vue router (based on sample from here).
My question is, from within my vue application, how can I access the JWT token (set by the login REST API in the HTTP Headers of the response) and store it in my vuex store so that my vue components can use it?
Thanks for your help!
PS: I am using node.js 8.5, Vue 2.4.4, Vue Router 2.7, Vuex 2.4.1
Use Axios Interceptors:
import { defaults, get } from 'lodash';
import axios from 'axios';
import store from 'vuex-store';
import def from './default';
export const connection = (options = {}) => {
def.headers = { Authorization: store.getters.auth.getToken() };
const instance = axios.create(defaults(def, options));
instance.interceptors.response.use(
function (response) {
const newtoken = get(response, 'headers.authorization');
if (newtoken) store.dispatch('setToken', newtoken);
console.log(response.data);
return response;
},
function (error) {
switch (error.response.status) {
case 401:
store.dispatch('logoff');
break;
default:
console.log(error.response);
}
return Promise.reject(error);
}
);
return instance;
};

Resources