Hi I would like to send an email to myself from my gatsby site in development. I have tried to follow this guide
I have set up the project like:
/client (gatsby site running on port 8000)
----package.json
server.js (node server running on port 3000)
----package.json
Here is my server.s code:
require("dotenv").config({
path: `.env`,
})
const port = 3000
const bodyParser = require("body-parser")
const express = require("express")
const nodemailer = require("nodemailer")
const morgan = require('morgan')
const app = express()
app.use(morgan('dev'))
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
const contactAddress = "myemail#gmail.com"
const mailer = nodemailer.createTransport({
service: "Gmail",
auth: {
user: process.env.GMAIL_ADDRESS,
pass: process.env.GMAIL_PASSWORD,
},
})
app.get('/', function (req, res) {
res.send('The server is running...')
})
app.post("/contact", function (req, res) {
console.log('post request')
mailer.sendMail(
{
from: req.body.name,
to: [contactAddress],
subject: "Message from website",
html: req.body.message,
},
function (err, info) {
if (err) {
console.log(err)
return res.status(500).send(err)
} else {
//success
console.log('worked')
res.json({ success: true })
}
}
)
})
app.listen(port, () =>
console.log(`Mail server listening on port ${port}!`)
);
The form action is like:
<form css={containerStyle} name="contact" method="post" action="http://localhost:3000/contact">
<FormComponents />
</form>
So far it is not logging to console or sending an email. Any pointers where I am going wrong would help. Thanks.
I solved it. Basically, i didn't understand how express worked - you need to include cors in express. And use Axios to send the form data
Answer here helped me
Related
I am trying to send a 'POST' XMLHttpRequest to my server, which uses express.
The server is able to recieve the request, but the request's body is null.
On the server I am receiving it with :
app.post('/', function(req, res){
res.send(req.statusCode);
console.log(req.body);
})
I don't think that there is a problem with it as many sources say that this is a good way to receive the request.
This is my client side code :
const user = {
'Key' : 'user',
'Name' : 'user',
'Email' : 'user#example.com',
'Password' : 'password'
}
const jsonFileRequest = new XMLHttpRequest();
jsonFileRequest.open('POST', '/', true);
jsonFileRequest.setRequestHeader('Content-Type', 'application/json');
jsonFileRequest.onreadystatechange = function(){
console.log(`userStatus : ${jsonFileRequest.readyState},\nstatus: ${jsonFileRequest.status}`);
if(jsonFileRequest.readyState == 4 && jsonFileRequest.status == 200)
{
console.log(`userStatus : ✅,\nstatus : ✅`);
}
}
jsonFileRequest.send(JSON.stringify(user));
**This is my server side code : **
const express = require('express');
const app = express();
const port = 8080;
app.get('/', (req, res) => {
res.sendFile(__dirname + '/frontend/index.html');
app.get('/index.html.js', (req, res) => {
res.sendFile(__dirname + '/frontend/index.html.js');
})
app.get('/data.json', (req, res) => {
res.sendFile(__dirname + '/data.json');
})
})
app.post('/', function(req, res){
res.send(req.statusCode);
console.log(req.body);
})
app.listen(port);
console.log(`listening on http://localhost:${port}`);
Could you please help me? Thank you!
You should try using the express.json() middleware. When disabled (by default), req.body returns undefined.
You can check out the express documentation for more info:
req.body
Contains key-value pairs of data submitted in the request
body. By default, it is undefined, and is populated when you use
body-parsing middleware such as express.json() or
express.urlencoded().
See: https://expressjs.com/en/api.html
Using the following code snippet for your express server should work:
// Importing the express module
var express = require('express');
// Initializing the express and port number
var app = express();
var PORT = 3000;
// Calling the express.json() method for parsing
app.use(express.json());
// Reading content-type
app.post('/', function (req, res) {
console.log(req.body.name)
res.end();
})
// Listening to the port
app.listen(PORT, function(err){
if (err) console.log(err);
console.log("Server listening on PORT", PORT);
});
You will need a parser for the data/body you are sending. By default express does not parse the body part of the request.
You can add these two line in your express server to fix this.
app.use(express.json())
app.use(express.urlencoded({ extended: true}));
I am trying to start my nestJs server and It keeps giving me this error:
UnhandledPromiseRejectionWarning: Error: You must await server.start() before calling server.applyMiddleware()
at ApolloServer
I'm not even sure where to debug from as I am still very new at NestJs and GraphQL.
This is a known bug with an open issue and a merged PR to fix it. For now, you can downgrade to apollo-server-express#^2
A complete working code is:
const express = require("express");
const { ApolloServer } = require("apollo-server-express");
const http = require("http");
const app = express();
const typeDefs = `
type Query{
totalPosts: Int!
}
`;
const resolvers = {
Query: {
totalPosts: () => 100,
},
};
let apolloServer = null;
async function startServer() {
apolloServer = new ApolloServer({
typeDefs,
resolvers,
});
await apolloServer.start();
apolloServer.applyMiddleware({ app });
}
startServer();
const httpserver = http.createServer(app);
app.get("/rest", function (req, res) {
res.json({ data: "api working" });
});
app.listen(4000, function () {
console.log(`server running on port 4000`);
console.log(`gql path is ${apolloServer.graphqlPath}`);
});
I faced this issue when upgrading Ben Awad's Graphql-Next-Typeorm[...] stack, simply adding an await to server start fixed the warnings
const apolloServer = new ApolloServer({
introspection: true,
schema: await buildSchema({
resolvers: [__dirname + '/resolvers/**/*.js'],
validate: false
}),
context: ({ req, res }) => ({
req,
res,
redis: redisClient
}),
formatError
});
// added this line
await apolloServer.start();
apolloServer.applyMiddleware({
app,
cors: false
});
For Apollo Server Express 3.0 and above, you need to define an async function that takes in typeDefs and resolvers parameters, then assign the server to the same Apollo initialization as before as shown here
async function startApolloServer(typeDefs, resolvers){
const server = new ApolloServer({typeDefs, resolvers})
const app = express();
await server.start();
server.applyMiddleware({app, path: '/graphql'});
app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}${server.graphqlPath}`);
})
}
startApolloServer(typeDefs, resolvers);
downgrading is not the option (at least anymore)
here is the solution =>
https://javascriptsu.wordpress.com/2021/08/02/apollo-error-must-await-server-start/
const server = new ApolloServer({ typeDefs, resolvers });
const app = express();
server.start().then(res => {
server.applyMiddleware({ app });
app.listen({ port: 3000 }, () =>
console.log("nice")
)
})
You can put everything in an async function and execute the function in your server(app,index...).js. You may also check the npm package.
https://www.npmjs.com/package/apollo-server-express
For example:
const express = require('express')
, http = require('http')
, path = require('path');
const { ApolloServer } = require('apollo-server-express');
async function startExpressApolloServer() {
const { typeDefs } = require('./graphql/schemas/schema');
const { resolvers } = require('./graphql/resolvers/resolver');
const server = new ApolloServer({ typeDefs, resolvers });
await server.start();
const app = express();
server.applyMiddleware({ app, path: '/api/graphql' });
await new Promise(resolve => app.listen({ port: 3001 }, resolve));
console.log(`Server ready at http://localhost:3001${server.graphqlPath}`);
return { server, app };
}
startExpressApolloServer();
I had the same type of problem. I was using TypeScript, Express, ApolloServer. What I did-
async function a(){
const server = new ApolloServer({ typeDefs, resolvers });
await server.start();
server.applyMiddleware({ app, path: '/graphql' });
}
a();
This is not a bug. As per the documentation, the Apollo server needs to be instantiated in an async function. This is the recommended setup for Apollo Express:
import { ApolloServer } from 'apollo-server-express';
import { ApolloServerPluginDrainHttpServer } from 'apollo-server-core';
import express from 'express';
import http from 'http';
async function startApolloServer(typeDefs, resolvers) {
const app = express();
const httpServer = http.createServer(app);
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
});
await server.start();
server.applyMiddleware({ app });
await new Promise(resolve => httpServer.listen({ port: 4000 }, resolve));
console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`);
}
There are already some great answers here. But we should know why and where we should call server.start(). From apollo docs -
Always call await server.start() before calling
server.applyMiddleware and starting your HTTP server. This allows
you to react to Apollo Server startup failures by crashing your
process instead of starting to serve traffic.
One other option is to downgrade your apollo to any 2.x.x. It solved my problem
This is my working server:
import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import typeDefs from './schema';
const app = express();
const server = new ApolloServer({
typeDefs,
mocks: true
});
server.start().then(() => {
server.applyMiddleware({
app,
cors: true,
});
});
const PORT = 4000;
app.listen(PORT, () => {
console.log(
`GraphQL endpoint and playground accessible at http://localhost:${PORT}${server.graphqlPath}`,
);
});
The key thing here is to wrap the "applyMiddleware" function call inside the "server.start" async function.
In v3, if you use apollo-server-express the start function is required https://www.apollographql.com/docs/apollo-server/api/apollo-server/#start.
You can do something like this.
const app = express()
app.use(express.urlencoded({ extended: true }))
app.use(express.json())
....
export const startup = async () => {
await server.start()
server.applyMiddleware({ app, path: `/api/${configs.region}/graphql` })
return app
}
// call startup in another file to get app
It is not ok to start the apollo server in advance. What happens with the case when I have to explicitly use http/https. Please see the following case:
const server = new ApolloServer({
typeDefs: [KeycloakTypeDefs, typeDefs], // 1. Add the Keycloak Type Defs
schemaDirectives: KeycloakSchemaDirectives, // 2. Add the
formatError: new ApolloErrorConverter(),
resolvers: resolvers,
context: ({ req }) => {
return makeContextWithDependencies(req);
}
});
server.applyMiddleware({ app });
http.createServer(app).listen(config.server.port, os.hostname());
const options = {
key: fs.readFileSync(config.server.ssl.keyFile, "utf8"),
cert: fs.readFileSync(config.server.ssl.certFile, "utf8"),
passphrase: config.server.ssl.passphrase
};
https
.createServer(options, app)
.listen(config.server.securePort, os.hostname());
console.log(
"Server waiting for requests on ports: " +
config.server.port +
"," +
config.server.securePort
);
We must wait for the server to get ready before adding middleware to it.
const app = express();
const apolloServer = new ApolloServer({
schema: await buildSchema({
resolvers: [HelloResolver],
validate: false,
}),
});
await apolloServer.start(); // First start the server then apply middleware on it
apolloServer.applyMiddleware({ app });
you can do like that, it works for me.
const server = new ApolloServer({ schema });
const startApollo = async () => {
try {
await server.start();
server.applyMiddleware({ app, path: "/api"})
} catch (error) {
console.log(error);
}
}
I have my express server on a different port than my client-side nextjs project.
I know when you have a server on the same port you can use getRequestHandler with next that passes the user object to be accessible with getInitialProps in the client-side.
const express = require("express");
const next = require("next");
const app = next({ dev: true });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
// adds passport session
require("./middlewares").init(server);
const apolloServer = require("./graphql").createApolloServer();
apolloServer.applyMiddleware({ app: server });
server.all("*", (req, res) => {
return handle(req, res);
});
server.listen(port, (err) => {
if (err) throw err;
});
});
My passport implementation is as follows
const config = require("../config");
const session = require("express-session");
const passport = require("passport");
exports.init = (server, db) => {
require("./passport").init(passport);
const sess = {
name: "pid",
secret: config.SESSION_SECRET,
cookie: { maxAge: 2 * 60 * 60 * 1000 },
resave: false,
saveUninitialized: false,
store: db.initSessionStore(),
};
if (process.env.NODE_ENV === "production") {
server.set("trust proxy", 1);
sess.cookie.secure = true;
sess.cookie.httpOnly = true;
sess.cookie.sameSite = 'none';
sess.cookie.domain = process.env.DOMAIN;
}
server.use(session(sess));
server.use(passport.initialize());
server.use(passport.session());
};
And running the following on the express server, I can see req.user returning the user object.
app.use((req, res, next) => {
console.log(req.user);
next();
});
In a page in my nextjs app, in getInitialProps req.user is undefined
Home.getInitialProps = async (ctx) => {
const { req } = ctx;
const { user } = req;
console.log(user);
..........
};
Is there a way to either access the passport user object via SSR in nextjs or a different method to authorize and user on a page?
I do have a Github Repo with instructions on how to run the app in the README.md
Passport auth doesn't seems work across port. The solution is put a ngnix in front.
Local passport authorization on different ports
I am attempting to deploy a server to an azure app service. The server code can be found below.
The error I am getting from the log stream is:
2020-11-18T23:36:06.088Z ERROR - Container [container name] didn't respond to HTTP pings on port: 8080, failing site start. See container logs for debugging.
I have PORT set to 8080 and I know that config is picking up as I can see "Server listening on port 8080" in the logs. I have tried changing WEBSITES_PORT to 80 and 8080 as I saw that other posts, but I think my issue is different.
This site was working prior to my adding auth with OIDC libraries.
The app works locally with the server code below.
const https = require('https')
const express = require('express')
const path = require('path')
const app = express()
const fs = require('fs')
const key = fs.readFileSync('./key.pem')
const cert = fs.readFileSync('./cert.pem')
require('dotenv').config()
app.use(express.json())
app.use(express.urlencoded({
extended: true
}))
app.use(express.static('express'))
var cors = require('cors')
const OktaJwtVerifier = require('#okta/jwt-verifier')
const session = require('express-session')
const {
ExpressOIDC
} = require('#okta/oidc-middleware')
var getUserInfo = require('./getUserInfo')
// session support is required to use ExpressOIDC
app.use(
session({
secret: 'this should be secure',
resave: true,
saveUninitialized: false,
cookie: {
httpOnly: false,
secure: true,
},
})
)
const oidc = new ExpressOIDC({
issuer: process.env.ISSUER || 'https://[custom auth server domain].gov/oauth2/default',
client_id: process.env.CLIENT_ID || 'xxxxxxxxxxxxxxxxx',
client_secret: process.env.CLIENT_SECRET || 'xxxxxxxxxxxxxxxxxx',
redirect_uri: process.env.REDIRECT_URI ||
'https://localhost:3000/authorization-code/callback',
appBaseUrl: process.env.APP_BASE_URL || 'https://localhost:3000',
scope: 'openid profile',
})
// ExpressOIDC attaches handlers for the /login and /authorization-code/callback routes
app.use(oidc.router)
app.use(cors())
app.options('*', cors())
app.get('/userinfo', (req, res) => {
let domain = 'dev'
if (req.isAuthenticated()) {
getUserInfo.userRequest(res, req.userContext, domain)
}
})
app.get('/authStatus', (req, res) => {
if (req.isAuthenticated()) {
res.send(req.userContext.userinfo)
}
})
app.post('/forces-logout', oidc.forceLogoutAndRevoke(), (req, res) => {
// Nothing here will execute, after the redirects the user will end up wherever the `routes.logoutCallback.path` specifies (default `/`)
})
var linkObj = {not relevant links used hrefs on html based on env}
// default URL for website
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/express/index.html'))
//__dirname : It will resolve to your project folder.
})
// FAQ Path
app.get('/help', function(req, res) {
res.sendFile(path.join(__dirname + '/express/help.html'))
//__dirname : It will resolve to your project folder.
})
app.get('/links', (req, res) => {
res.json(linkObj)
})
app.post('/forces-logout', oidc.forceLogoutAndRevoke(), (req, res) => {
// Nothing here will execute, after the redirects the user will end up wherever the `routes.logoutCallback.path` specifies (default `/`)
})
// default URL for website
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname + '/express/index.html'))
//__dirname : It will resolve to your project folder.
})
const port = normalizePort(process.env.PORT || '3000')
if (process.env.PORT) {
const server = https.createServer(app)
server.listen(port)
} else {
const server = https.createServer({
key: key,
cert: cert
}, app)
server.listen(port)
}
console.debug('Server listening on port ' + port)
function normalizePort(val) {
var port = parseInt(val, 10)
if (isNaN(port)) {
// named pipe
return val
}
if (port >= 0) {
// port number
return port
}
return false
}
I believe it's this line that could be giving you issues:
const port = normalizePort(process.env.PORT || '3000')
I'd try changing it to:
const port = normalizePort(process.env.PORT || '8080')
You'll also need to change these lines to have your public URL, not localhost:
redirect_uri: process.env.REDIRECT_URI ||
'https://localhost:3000/authorization-code/callback',
appBaseUrl: process.env.APP_BASE_URL || 'https://localhost:3000',
After you change these, you'll need to update your app on Okta to your production redirect URI.
I have passport.js set up with strategies for Google, Facebook and Github. They work fine over HTTP but not so in HTTPS.
When I'm on my site over HTTPS, and I click for example, Login with Google, I see in my URL bar the site has sent me to the relative URL '/auth/google'. This is the route I've wired in my backend to initiate the OAuth process for logging in. But in HTTPS, I simply end up at the page, there are no error messages in dev console. I have a catch all block of code that serves up index.html when the URL doesn't match any of my routes and I'm pretty sure this is what's happening i.e. the backend routes doesn't seemed to be recognised.
So to summarise, on HTTP, the app stays in a non-logged in state and there are no errors in the dev console.
What's worth noting is that I can also get it to stay in logged in state with the same behaviour as well. If I log in over HTTP and then immediately go to the HTTPS site, I'm logged in. If I try to log out, I get sent to '/auth/logout'. Again no error in console and I get served index.html as if I hadn't written a route for '/auth/logout' and I continue to be logged in.
Because there are no error messages, I don't know what part of the code to show here, I'll just show what I think could be possibly relevant.
Here are my auth routes:
const passport = require('passport')
const express = require('express')
const auth = express.Router()
auth.get(
'/google',
passport.authenticate('google', {
scope: ['profile']
})
)
auth.get('/google/callback', passport.authenticate('google'), (req, res) => {
res.redirect('/')
})
auth.get('/facebook', passport.authenticate('facebook'))
auth.get(
'/facebook/callback',
passport.authenticate('facebook'),
(req, res) => {
res.redirect('/')
}
)
auth.get('/github', passport.authenticate('github'))
auth.get('/github/callback', passport.authenticate('github'), (req, res) => {
res.redirect('/')
})
auth.get('/current_user', (req, res) => {
res.send(req.user)
})
auth.get('/logout', (req, res) => {
req.logout()
res.redirect('/')
})
module.exports = auth
Here is my passport strategies
const passport = require('passport')
const GoogleStrategy = require('passport-google-oauth20').Strategy
const FacebookStrategy = require('passport-facebook').Strategy
const GithubStrategy = require('passport-github').Strategy
const mongoose = require('mongoose')
const keys = require('../config/keys')
const User = mongoose.model('user')
passport.serializeUser((user, done) => {
done(null, user.id)
})
passport.deserializeUser((id, done) => {
User.findById(id).then(user => {
done(null, user)
})
})
const login = (accessToken, refreshToken, profile, done) => {
User.findOne({ profileID: profile.id }).then(existingUser => {
if (existingUser) {
done(null, existingUser)
} else {
new User({
profileID: profile.id
})
.save()
.then(user => done(null, user))
}
})
}
passport.use(
new GoogleStrategy(
{
clientID: keys.googleClientID,
clientSecret: keys.googleSecretKey,
callbackURL: '/auth/google/callback',
proxy: true
},
login
)
)
passport.use(
new FacebookStrategy(
{
clientID: keys.facebookClientID,
clientSecret: keys.facebookSecretKey,
callbackURL: '/auth/facebook/callback',
profileFields: ['id', 'name'],
proxy: true
},
login
)
)
passport.use(
new GithubStrategy(
{
clientID: keys.githubClientID,
clientSecret: keys.githubSecretKey,
callbackURL: '/auth/github/callback',
proxy: true
},
login
)
)
And here is my server index.js
const express = require('express')
const mongoose = require('mongoose')
const passport = require('passport')
const session = require('express-session')
const bodyParser = require('body-parser')
const keys = require('./config/keys')
const auth = require('./routes/authRoutes')
const poll = require('./routes/pollRoutes')
require('./models/User')
require('./services/passport')
mongoose.connect(keys.mongoURI, { useMongoClient: true })
mongoose.Promise = global.Promise
const app = express()
app.use(bodyParser.json())
app.use(
session({
secret: keys.cookieKey,
saveUninitialized: true,
resave: true
})
)
app.use(passport.initialize())
app.use(passport.session())
app.use('/auth', auth)
app.use('/poll', poll)
if (process.env.NODE_ENV === 'production') {
app.use(express.static('client/build'))
const path = require('path')
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'))
})
}
const PORT = process.env.PORT || 5000
app.listen(PORT, () => console.log(`Server started on port ${PORT}`))
I'll also provide a link to my Heroku app so you guys can see the buggy behaviour over HTTPS and a link to my Github repo
I'm pretty sure this doesn't have anything to do with how I've set up my Oauth on developer consoles of Google, Facebook and Github because all three login strategies behave exactly the same way so I would have to set up the Google+ API credentials, the Facebook Login settings and the Github Developers Settings all in a way to produce the same error which seems really unlikely. Also everything works correctly on LocalHost. Can someone please help me with this issue?