ERROR 500 on axios API Call in Next JS after deployment to Vercel - deployment

I am using a simple API to send Emails via axios and nodemailer in Next JS.
Locally everythings works normally, after deployment to Vercel i am getting Error 500 when trying to send an Email.
This is from the Form Component:
async function onSubmitForm(values) {
setLoading(true);
let config = {
method: "post",
url: `${env.process.NEXT_LINK}/api/contact`,
headers: {
"Content-Type": "application/json",
},
data: values,
};
try {
const response = await axios(config);
setLoading(false);
setSuccess(true);
} catch (err) {
console.log("frontend error", err);
}
}
Getting this Error in Dev Tools:
frontend error
o {message: 'Request failed with status code 500', name: 'AxiosError', code: 'ERR_BAD_RESPONSE', config: {…}, request: XMLHttpRequest, …}
code
:
"ERR_BAD_RESPONSE"
config
:
{transitional: {…}, transformRequest: Array(1), transformResponse: Array(1), timeout: 0, adapter: ƒ, …}
message
:
"Request failed with status code 500"
name
:
"AxiosError"
request
:
XMLHttpRequest {onreadystatechange: null, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, …}
response
:
{data: '', status: 500, statusText: '', headers: {…}, config: {…}, …}
[[Prototype]]
:
Error
The contact API File:
import handlebars from "handlebars";
const nodemailer = require("nodemailer");
const path = require("path");
const fs = require("fs");
export default async (req, res) => {
const { firstName, name, email, message, phone } = req.body;
const transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 465,
secure: true,
auth: {
user: process.env.NEXT_USER,
pass: process.env.NEXT_GMAIL,
},
});
await new Promise((resolve, reject) => {
// verify connection configuration
transporter.verify(function (error, success) {
if (error) {
console.log(error);
reject(error);
} else {
console.log("Server is ready to take our messages");
resolve(success);
}
});
});
const filePath = path.join(__dirname, "../../../../components/form/html/template.html");
const source = fs.readFileSync(filePath, "utf-8").toString();
const template = handlebars.compile(source);
const replacements = {
name: name,
email: email,
phone: phone,
message: message,
};
const htmlToSend = template(replacements);
await new Promise((resolve, reject) => {
if (!firstName) {
try {
const emailRes = transporter.sendMail({
from: email,
to: {process.env.NEXT_MYEMAIL},
subject: `Email von ${name}`,
html: htmlToSend,
});
console.log("Message Sent", emailRes.messageId);
res.status(200).json(req.body);
} catch (err) {
console.log("GEHT NET", err);
}
} else {
res.status(403).json(req.body);
}
});
console.log(req.body, "Test");
};
Package JSON:
{
"name": "default_next",
"version": "0.1.0",
"private": true,
"main": "index.js",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"export": "next build && next export",
"lint": "next lint"
},
"dependencies": {
"#amir04lm26/react-modern-calendar-date-picker": "^1.0.1",
"#palmabit/react-cookie-law": "^0.7.0",
"#portabletext/react": "^1.0.6",
"#sanity/asset-utils": "^1.3.0",
"#sanity/client": "^3.3.2",
"#sanity/image-url": "^1.0.1",
"animate.css": "^4.1.1",
"axios": "^0.27.2",
"framer-motion": "^7.1.0",
"handlebars": "^4.7.7",
"next": "12.1.6",
"next-sanity-image": "^3.2.1",
"next-useragent": "^2.8.0",
"nodemailer": "^6.7.8",
"react": "18.2.0",
"react-animate-on-scroll": "^2.1.5",
"react-collapsed": "^3.3.2",
"react-cookie-consent": "^8.0.1",
"react-device-detect": "^2.2.2",
"react-dom": "18.2.0",
"react-hook-form": "^7.34.2",
"react-icons": "^4.4.0",
"react-loader-spinner": "^5.3.3",
"react-modern-calendar-datepicker": "^3.1.6",
"react-spring": "^9.4.5",
"react-sticky": "^6.0.3",
"react-use-scroll-snap": "0.0.4",
"react-visibility-sensor": "^5.1.1",
"swiper": "^8.3.0"
},
"devDependencies": {
"autoprefixer": "^10.4.7",
"eslint": "8.17.0",
"eslint-config-next": "12.1.6",
"eslint-plugin-react": "^7.30.1",
"postcss": "^8.4.14",
"tailwindcss": "^3.1.3"
}
}
I declared all env variables in Vercel.
The Error logs in the Component File, but the path to the API is correct.
I tried hardcoding the Api path, checking all the env variables on Vercel, changing the path to see the Error Message (Error 404).
Ran it again locally, everything works there.

SOLUTION:
I looked into the Vercel functions logs and got an error for the handlebars template file. File not found. Removed handlebars from API and it worked!

Related

Why do I keep getting this error when I try to connect mongodb to my next.js project

I keep getting this error when I try to connect my mongodb to my user api route file. I don't know what is going wrong and I do not know how to solve it, but I'm sure this is what my teacher wrote on his computer and it worked without any errors.
This is what my dbconnection file looks like
// MongoDB Connection
import mongoose from "mongoose";
if (!process.env.MONGODB_URL) {
throw new Error("Please define the MONGODB_URL environment variable inside .env.local");
}
let cached = global.mongoose;
if (!cached) {
cached = global.mongoose = { conn: null, promise: null };
}
async function dbConnect() {
if (cached.conn) {
return cached.conn;
}
if (!cached.promise) {
const opts = {
bufferCommands: false,
};
cached.promise = mongoose.connect(process.env.MONGODB_URL, opts).then((mongoose) => {
return mongoose;
});
}
cached.conn = await cached.promise;
return cached.conn;
}
export default dbConnect;
And this is how I define my user routes to the /api/user endpoint
import Users from "../../../api/models/Users";
import dbConnect from "../../util/mongo";
export default async function handler(req, res) {
const { method } = req;
dbConnect()
switch (method) {
case "GET":
try {
const res = await Users.find();
res.status(200).json(res);
} catch (error) {
res.status(500).json(error);
}
break;
case "POST":
console.log(POST);
break;
case "PUT":
console.log(PUT);
break;
case "Delete":
console.log(Delete);
break;
}
}
my package.json file is thus:
"name": "smooon",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"axios": "^1.1.0",
"mongodb": "^3.7.3",
"mongodb-client-encryption": "^2.3.0",
"mongoose": "^6.6.5",
"next": "12.3.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-snowfall": "^1.2.1",
"react-spinners-kit": "^1.9.1",
"react-tinder-card": "^1.5.4"
},
"devDependencies": {
"eslint": "8.23.1",
"eslint-config-next": "12.3.1"
}
}

jest calls afterEach (teardown) before test finish only in debug mode

I am using nodejs, nestjs, supertest, mongodb, mongoose.
My tests run is completed successfully, using command
npm run test:e2e from default nestjs package.json config.
When I execute my separate test in debug mode, from vscode debug view it fails with error of disposed mongodb connection. The test has mutliple async requests calls which I await it returns after request is called and starts executing jest teardown afterEach and afterAll which is kinda strange for me.
My launch.json
{
"type": "node",
"request": "launch",
"name": "Jest Current File e2e tests",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": [
"${fileBasenameNoExtension}",
"--config",
"${workspaceFolder}/test/jest-e2e.json"
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"disableOptimisticBPs": true,
"windows": {
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
}
}
jest-e2e.json
{
"moduleFileExtensions": ["js", "json", "ts"],
"rootDir": ".",
"testEnvironment": "node",
"testRegex": ".e2e-spec.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
}
}
app.e2e-spec.ts
describe('app (e2e)', () => {
let app: INestApplication;
let connection: Connection;
let dbInitializer: DbInitializer;
beforeAll(async () => {
const moduleFixture: TestingModule = await createAndCompileTestingModule();
app = moduleFixture.createNestApplication();
await configApp(app);
await app.init();
});
afterAll(async () => {
await app.close();
});
beforeEach(async () => {
const configService = app.get(ConfigService);
const logger = new MyLogger(configService);
connection = app.get(CustomConnectionService).getConnection();
dbInitializer = new DbInitializer(connection, logger);
await dbInitializer.seedDb();
});
afterEach(async () => {
await connection.db.dropCollection(dbInitializer.articleCollectionName);
await connection.db.dropCollection(dbInitializer.userCollectionName);
});
it('/ (POST) creates article', async function () {
expect.assertions(9);
const userToLogin = {
username: 'leane1Gra',
password: 'cft0id32',
};
const httpServer = app.getHttpServer();
const responseLogin = await request(httpServer)
.post(`/${LoginEndPoint}`)
.set('Accept', 'application/json')
.send(userToLogin);
expect(responseLogin.statusCode).toBe(201);
const userLoginResponse = responseLogin.body as UserLoginResponse;
const resposeGetUser = await request(app.getHttpServer())
.get(`/${UsersEndpoint}/by-username`)
.query({ username: userToLogin.username });
expect(resposeGetUser.statusCode).toBe(200);
const userFindByUsernameResponse =
resposeGetUser.body as MappedUserResponse;
const articleToCreate = {
title: 'article a',
subtitle: 'subtitle a',
description: 'description a',
category: 'history',
ownerId: userFindByUsernameResponse.id,
};
const response = await request(httpServer)
.post(`/${ArticlesEndpoint}`)
.set('Authorization', `Bearer ${userLoginResponse.user_jwt}`)
.set('Accept', 'application/json')
.send(articleToCreate);
expect(response.statusCode).toBe(201);
expect(response.headers['content-type']).toMatch(/json/);
const { updatedUser, newArticle } = response.body as CreateArticleResponse;
expect(newArticle.id).toBeTruthy();
expect(newArticle.title).toBe(articleToCreate.title);
expect(updatedUser.id).toBeTruthy();
expect(updatedUser.articleIds).toContain(newArticle.id);
expect(updatedUser.numberOfArticles).toBe(
userFindByUsernameResponse.numberOfArticles + 1,
);
});
}
I am adding a video of test run in debug mode
Add the timeout after your it test. The max value for timeout is 32 bit signed integer.
You can debug your test during specified timeout without jest teardown called.
it('/ (POST) creates article', async function () {
//test body omitted
},147483647)

Puppeteer + Leaflet JS with Apple MapKit PDF Creation Issues

I'm having issues properly exporting a PDF when using Apple MapKit tiles. It works fine with Google Maps or Bing tiles.
Expected output:
Actual output:
Notice the tiles zoomed incorrectly.
How to reproduce the issue:
Use the following curl command with a local Puppeteer server:
curl -X GET -G "http://localhost:8080" --data-urlencode "url=https://en.mycoursewalk.com/coursewalks/18624/print?print_pdf=true&unlisted_id=e61d9b86d7" --data-urlencode "page_orientation=Landscape" --data-urlencode "paper_size=Letter" --output "test.pdf"
You can access the page in your browser at: https://en.mycoursewalk.com/coursewalks/18624/print?unlisted_id=e61d9b86d7
package.json
{
"name": "chrome-puppeteer-pdf-export",
"version": "1.0.1",
"description": "",
"engines": {
"node": "12.22.6"
},
"main": "app.js",
"directories": {
"doc": "doc",
"lib": "lib",
"test": "test"
},
"scripts": {
"start": "node app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"express": "^4.17.1",
"valid-url": "^1.0.9",
"puppeteer": "10.4.0"
}
}
app.js
const express = require('express');
const app = express();
const puppeteer = require('puppeteer');
const port = process.env.PORT || 8080;
const validUrl = require('valid-url');
const parseUrl = function(url) {
url = decodeURIComponent(url);
if (!/^(?:f|ht)tps?\:\/\//.test(url)) {
url = 'http://' + url;
}
return url;
};
app.get('/', function(req, res) {
const urlToScreenshot = parseUrl(req.query.url);
if (validUrl.isWebUri(urlToScreenshot)) {
console.log('Screenshotting: ' + urlToScreenshot);
const page_orientation = req.query.page_orientation;
const paper_size = req.query.paper_size;
(async() => {
let browser;
try {
browser = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const page = await browser.newPage();
await page.emulateMediaType('print');
await page.setCacheEnabled(false);
await page.setViewport({ width: 1024, height: 768, deviceScaleFactor: 2 });
await page.goto(urlToScreenshot, { timeout: 30000, waitUntil: 'networkidle0' });
await page.waitFor(250);
await page.pdf({
format: paper_size,
landscape: (page_orientation === 'Landscape'),
margin: { top: 36, right: 36, bottom: 20, left: 36 },
printBackground: true
}).then(function(buffer) {
res.setHeader('Content-Disposition', 'attachment;filename="export.pdf"');
res.setHeader('Content-Type', 'application/pdf');
res.send(buffer)
});
} catch (err) {
console.log(err.message);
} finally {
if (browser) {
browser.close();
}
}
})();
} else {
res.send('Invalid url: ' + urlToScreenshot);
}
});
app.listen(port, function() {
console.log('App listening on port ' + port)
});
UPDATE
The problem is only happening for maps that end up on a fractional zoom level. I allow a zoom step of 0.25.
The problem only happens with the Apple MapKit tiles. It works fine with the Google Maps or Bing.
The expected output screenshot above is taken by printing to PDF from the Google Chrome browser. The map also displays correctly in the browser. The problem only happens when generating a PDF using Puppeteer

Why it is reflecting undefined in Mongodb server

I'm new to mongoDb and took one course but stuck at this point .I created this Index.js and here I'm inserting one data and using callbacks but after insertion it is reflecting undefined?
--indes.js
const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
const url = 'mongodb://localhost:27017/';
const dbname = 'conFusion';
MongoClient.connect(url, (err, client) => {
assert.equal(err, null);
console.log('Connected correctly to server');
const db = client.db(dbname);
const collection = db.collection('dishes');
collection.insertOne({ "name": "Uthappizza1", "description": "test" },
(err, result) => {
assert.equal(err, null);
console.log('After Insert:\n');
console.log(result.ops);
collection.find({}).toArray((err, docs) => {
assert.equal(err, null);
console.log('Found:\n');
console.log(docs);
db.dropCollection('dishes', (err, result) => {
assert.equal(err, null);
client.close();
});
});
});
});
also attaching the package.json for more clearilty
{
"name": "node-mongo",
"version": "1.0.0",
"description": "Node MongoDB Example",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node index"
},
"author": "Shivam Singh",
"license": "ISC",
"dependencies": {
"assert": "^2.0.0",
"mongodb": "^4.0.1"
}
}
I'm also attaching the screenshot
It is because the insertOne method through the callback returns object of interface InsertOneResult, which according to the documentation only has 2 fields: acknowledged and insertedId. Due to this reason result.ops will always be undefined here because you do have result object, but it doesn't have the property ops.

EAI_AGAIN error while making SMTP connection in Loopback

datasource.json:
"emailDs": {
"name": "emailDs",
"connector": "mail",
"transports": [{
"type": "smtp",
"host": "smtp.myapp.in",
"secure": true,
"secureConnection": true,
"port": 587,
"tls": {
"rejectUnauthorized": false
},
"auth": {
"user": "name#myapp.in",
"pass": "pwd"
}
}]
}
model-config.json
"Email": {
"dataSource": "emailDs"
}
mymodel.js (Extends default loopbacl's user model)
var options = {
type: 'email',
to: myUser.email,
from: 'name#myapp.in',
subject: 'Thanks for registering.',
template: path.resolve(__dirname, '../../server/views/verify.ejs'),
redirect: '/verified',
entrepreneur: entrepreneur
};
myUser.verify(options, function(err, response) {
if (err) {
next(err);
return;
}
When I am creating new user, this afterRemote 'create' code is running but while sending mail it is giving following error:
{
"error": {
"name": "Error",
"status": 500,
"message": "getaddrinfo EAI_AGAIN",
"code": "EAI_AGAIN",
"errno": "EAI_AGAIN",
"syscall": "getaddrinfo",
"hostname": "smtp.myapp.in",
"stack": "Error: getaddrinfo EAI_AGAIN\n at Object.exports._errnoException (util.js:746:11)\n at errnoException (dns.js:49:15)\n at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:94:26)"
}
}
I have created a new domain in Bigrock and using the free email service provided by them. Please suggest what am I doing wrong here.