Reputation: 69
Working in the MERN stack (Mongo, Express, React, Node) and running into an error in my API.
Here is my plaid.js
file where one of my routes is throwing this error. Of course, I've removed all of my secret token variables but assume everything works until the res.json error (which it does).
const express = require("express");
const plaid = require("plaid");
const router = express.Router();
const jwt = require("jsonwebtoken");
const keys = require("../../config/keys");
const passport = require("passport");
const moment = require("moment");
const mongoose = require("mongoose");
// Load Account and User models
const Account = require("../../models/Account");
const User = require("../../models/User");
// Replaced my actual keys with empty strings for sake of this post
const PLAID_CLIENT_ID = "";
const PLAID_SECRET = "";
const PLAID_PUBLIC_KEY = "";
const client = new plaid.Client(
PLAID_CLIENT_ID,
PLAID_SECRET,
PLAID_PUBLIC_KEY,
plaid.environments.sandbox,
{ version: "2018-05-22" }
);
var PUBLIC_TOKEN = null;
var ACCESS_TOKEN = null;
var ITEM_ID = null;
// @route POST api/plaid/accounts/add
// @desc Trades public token for access token and stores credentials in database
// @access Private
router.post(
"/accounts/add",
passport.authenticate("jwt", { session: false }),
(req, res) => {
PUBLIC_TOKEN = req.body.public_token;
const userId = req.user.id;
const institution = req.body.metadata.institution;
const { name, institution_id } = institution;
if (PUBLIC_TOKEN) {
client
.exchangePublicToken(PUBLIC_TOKEN)
.then(res => {
ACCESS_TOKEN = res.access_token;
ITEM_ID = res.item_id;
// Check if account already exists for specific user
Account.findOne({
userId: req.user.id,
institutionId: institution_id
})
.then(account => {
if (account) {
console.log("Account already exists");
} else {
const newAccount = new Account({
userId: userId,
publicToken: PUBLIC_TOKEN,
accessToken: ACCESS_TOKEN,
itemId: ITEM_ID,
institutionId: institution_id,
institutionName: name
});
// TO:DO fix error, res.json is not a function
newAccount.save().then(account => res.json(account));
}
})
.catch(err => console.log(err)); // Mongo Error
})
.catch(err => console.log(err)); // Plaid Error
}
}
);
module.exports = router;
The newAccount.save()
executes just fine, but the subsequent res.json
throws an error. This is the error that I am getting returned. Namely, res.json is not a function
.
[0] (node:23413) UnhandledPromiseRejectionWarning: TypeError: res.json is not a function
[0] at newAccount.save.then.account (/Users/rishi/plaid-auth/routes/api/plaid.js:97:55)
[0] at process._tickCallback (internal/process/next_tick.js:68:7)
There are quite a few posts on here with the res.json is not a function
error, but none of the proposed solutions worked for me. I am quite confused why this error is being thrown since I use the same convention in another part of the app and res.json
works just fine. See the below example of where res.json
works.
// @route POST api/posts
// @desc Create a post
// @access Private
router.post(
"/",
passport.authenticate("jwt", { session: false }),
(req, res) => {
const { errors, isValid } = validatePostInput(req.body);
// Check validation
if (!isValid) {
return res.status(400).json(errors);
}
const newPost = new Post({
text: req.body.text,
name: req.body.name,
avatar: req.body.avatar,
user: req.user.id // current logged in user
});
// res.json works just fine
newPost.save().then(post => res.json(post));
}
);
Upvotes: 0
Views: 4865
Reputation: 350
It's because this piece of code
if (PUBLIC_TOKEN) {
client
.exchangePublicToken(PUBLIC_TOKEN)
.then(res => {
ACCESS_TOKEN = res.access_token;
When you get to execute this line newAccount.save().then(account => res.json(account));
the res is not longer the one on the function router.post('/accounts/add', (req, res) => {})
So, the solution is simple, change the res from the promise exchangePublicToken into something else like the example below.
You are naming the parameter from the promise callback the same as the parameter on the callback from the router.post above
if (PUBLIC_TOKEN) {
client
.exchangePublicToken(PUBLIC_TOKEN)
.then(exchangeResponse => {
ACCESS_TOKEN = exchangeResponse.access_token;
Upvotes: 1