So...I have an api in Next js that uses Prisma Client. Prisma is imported from the global object defined in prisma.ts
Locally everything builds and runs fine. I get no errors and the prisma variable is defined.
However, when it's deployed in Vercel, prisma is undefined...I can't work out why.
If anyone has any suggestions, I'd much appreciate it.
import eBayApi from "#hendt/ebay-api";
import prisma from "../../lib/prisma";
const eBay = new eBayApi({});
export default async (req, res) => {
// Access the provided 'page' and 'limt' query parameters
const code = req.query.code; // this is provided from eBay
console.log(code);
try {
//const token = await eBay.OAuth2.getToken(code);
const token = "bob";
console.log("Prisma handler instance", prisma);
const env_variable = await prisma.variable.upsert({
where: {
variable: "EBAY_TOKEN",
},
update: { value: token },
create: {
variable: "EBAY_TOKEN",
value: token,
},
});
if (env_variable) {
console.log("New Token Stored in DB");
} else console.log("Failed to store new Token");
res.status(200);
res.writeHead(302, {
Location: "/orders",
//add other headers here...
});
res.end();
} catch (e) {
console.error(e);
res.status(400).end();
}
res.writeHead(302, {
Location: "/orders",
//add other headers here...
});
res.end();
};
2021-04-18T19:06:18.680Z 869eb228-423a-4d6a-b05a-f95f5e843c88 ERROR TypeError:
Cannot read property 'upsert' of undefined
at exports.modules.5712.webpack_exports.default (/var/task/nextjs-store/.next/server/pages/api/success.js:55:126)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async apiResolver (/var/task/nextjs-store/node_modules/next/dist/next-server/server/api-utils.js:8:1)
at async Server.handleApiRequest (/var/task/nextjs-store/node_modules/next/dist/next-server/server/next-server.js:67:462)
at async Object.fn (/var/task/nextjs-store/node_modules/next/dist/next-server/server/next-server.js:59:492)
at async Router.execute (/var/task/nextjs-store/node_modules/next/dist/next-server/server/router.js:25:67)
at async Server.run (/var/task/nextjs-store/node_modules/next/dist/next-server/server/next-server.js:69:1042)
at async Server.handleRequest (/var/task/nextjs-store/node_modules/next/dist/next-server/server/next-server.js:34:504)
at async Server. (/var/task/nextjs-store/___next_launcher.js:26:9)
So, I had a play around, and think I found the problem. My prisma table field was a VARCHAR (String), however I was inadvertently trying to store upsert with a JSON object.
Now that I've changed to a JSON field it's working.
So I guess the only problem is that maybe the error wasn't helpul?
Although it was all my stupid fault.
Related
I have a react project with NODE API backend. I am facing issues with the very basic fetch GET request. When passing parameters through link, it cannot be accessed at the server side.
My react function:
const loadOptions = async (cnt) => {
const response = await fetch(`${baseurl}/pdt/prev=${prev}&cnt=${cnt}`);
const resJSON = await response.json();
};
NodeJS express router code:
router.get("/pdt/:prev/:cnt", async (req, res) => {
try {
console.log(req.params.cnt);
console.log(req.params.prev);
} catch (err) {
res.json(err.message);
}
});
The result is :
Edited React code based on the answers I got above. Thank you #Phil
const response = await fetch(`${baseurl}/pdt/${prev}/${cnt}`);
It's working now.
another solution from backend
router.get("/pdt", async (req, res) => {
try {
console.log(req.query.prev);
console.log(req.query.cnt);
} catch (err) {
res.json(err.message);
}
});
and modify request
fetch(`${baseurl}/pdt?prev=${prev}&cnt=${cnt}`)
This is a course quiz and this is the most basic information I need in order to create a React app. But while the endpoint URL is correct, the page "/products" returns a "400" error when I try to request the product list. The instructions I'm given are:
Obtain a list of products with
Route: /products
Body: Array
method: POST
{
"product-codes": [
"98798729",
"84876871",
"29879879",
]
}
My index.js
...
app.post(`/products`, async (req, res) => {
try {
const response = await axios.post(`${apiURL}/products`);
// console.log(response.data);
res.status(200).json(response.data);
} catch (error) {
res.status(400).json({ message: error.message });
}
});
in Postman
I use http://localhost:4000/products
and pass a Body / Raw /JSON:
{
"product-codes": [
"98798729",
"84876871",
"29879879",
]
}
But I can't get in! I am not seeing something obvious because this is the entry point to a very long and complex quiz. Thanks
What I see from the code is a recursive long call.
app.post(`/products`, async (req, res) => {
try {
const response = await axios.post(`${apiURL}/products`); // calling the same end point
// console.log(response.data);
res.status(200).json(response.data);
} catch (error) {
res.status(400).json({ message: error.message });
}
});
You should do something like this:
app.post(`/products`, async (req, res) => {
// do your logic
// when you pass body from postman on this endpoint
// you will receive the body here and save it to DB
// or do the manipulation and then send back the response
res.status(200).json(req.body.data);
});
I highly recommend you to first follow through some tutorials to understand how API works and how to create simple API using Node.js.
I am not sure what is happening. I had all the same code setup in dev using localhost and everything was working fine. I hosted my app to Vercel and my API to heroku and from what I can tell the API is working perfectly. The issue now is when I make a post request I get a 400 Bad Request error in the browser but it still makes the request and posts to my DB I have setup. Any help can be appreciated. I built this application in a MERN stack with NEXT.js
Here is my client side Post request
const postSubmit = async e => {
e.preventDefault();
try {
const { data } = await axios.post('/create-post', { content, image });
if(data.error) {
toast.error(data.error);
} else {
setPage(1);
newsFeed();
toast.success("Post created");
setContent('');
setImage({});
// socket.emit('new-post', data);
}
} catch(e) {
console.log(e);
}
}
Here is my server side handling of the post request
export const createPost = async (req, res) => {
const { content, image } = req.body;
if(!content.length) {
return res.json({
error: 'Content is required'
})
}
try {
const post = new Post({ content, image, postedBy: req.user._id });
await post.save();
const postWithUser = await Post.findById(post._id).populate('postedBy', '-password -secret');
res.json(postWithUser);
} catch (e) {
console.log(e);
res.sendStatus(400);
}
};
And here is what the browser is telling me
Chrome Browser Info
This is most likely caused by a typo on the MongoDB connection string (URI), similar to this answer.
In the linked answer, the typo was the semi-colon in &w=majority;. In your case, the value is somehow majorityDATABASE=, so double-check your MongoDB connection string and try to remove the extra DATABASE= in the write concern parameter.
It's likely that the await Post.findById() call is not finding a result which could be throwing an error when you try to call res.json(postWihUser). That would then cause an error when postWithUser is not defined.
What is logged to the server's terminal when an error occurs? That should help you identify the problem.
So I'm new to AWS serverless architecture. I deployed my first lambda function using Claudia. I'm not sure whether I did it correctly. I deployed all the APIs to one lambda function using Claudia. The API endpoints works individually when I test it on Insomnia. But when I use it in my application only one specific API works and the lambda dies. For instance, I used this POST request to post some items and I have a useEffect in my React application which has a get request to retrieve all the items from the database. But once I post the item, nothing is returned. Could anyone help me understand what I'm doing wrong. P.S this is my final year project which is due in a few weeks. So, a quick answer would be appreciated.
Here is a sample code.
// Create a new Intake
router.post("/create", async (req, res) => {
const intake = req.body;
const { name, intakeCode, intakeYear } = req.body;
const checkIntake = await Intakes.findOne({
where: {
intakeCode: intakeCode,
},
});
if (checkIntake) {
res.json({ err: `An intake under ${intakeCode} already exists!` });
} else {
try {
await Intakes.create(intake);
res.json({ msg: `Successfully created ${name} ` });
} catch (e) {
if (e.name == "SequelizeDatabaseError") {
res.json({ err: "Year only accepts integer" });
} else {
res.json({ err: e.name });
}
}
}
});
// Find all Intakes
router.get("/findAll", async (req, res) => {
const listOfIntakes = await Intakes.findAll();
res.json(listOfIntakes);
});
Cheers
Looks like you are trying to build a Lambda function using JavaScript - but have encountered problems. I'm not familiar with Claudia. One suggestion that I have is to follow the official AWS SDK for JavaScript DEV Guide here:
https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/scheduled-events-invoking-lambda-example.html
That content will walk you through how to create a Lambda function using JS.
My end goal is that I want to be able to create a test that satisfies the following statement:
verify that requests to valid URLs return a 200 HTTP status code
A valid URL for example would be /about-page or /jobs, basically any directory that I add in my content folder that contains a file with the extension /index.md.
This is my code so far:
app.js
const readFilePromise = util.promisify(fs.readFile)
app.get('/*', (req, res) => {
readFilePromise(path.join(__dirname, 'content', req.url) + '/index.md', 'utf8')
.then(data => {
convertData(data, res)
})
.catch(err => {
res.status(404).send('Page doesn\'t exist!')
})
})
const convertData = (data, res) => {
const convertedData = md.render(data)
readFilePromise(path.join(__dirname, '/template.html'), 'utf8')
.then(data => {
data = data.replace(/\{\{content\}\}/, convertedData)
res.send(data)
})
.catch(err => {
console.log(err)
})
}
app.listen(3000)
module.exports = app
After reading this article, it mentions that
Requests are asynchronous, which means you must be able to conduct asynchronous tests.
So I wrote the following test:
app.test.js
const app = require('./app.js')
const request = supertest(app)
const supertest = require('supertest')
it('Gets the test endpoint and returns a 200 status', async done => {
const res = await request.get('/*')
expect(res.status).toBe(200)
done()
})
When I run the test, it fails with a 404 status, rather than returning a 200 status. I thought this might be due to my app.js not being in the async/await style, so I changed app.js to:
const readFilePromise = util.promisify(fs.readFile)
app.get('/*', async (req, res) => {
try {
await readFilePromise(path.join(__dirname, 'content', req.url) + '/index.md', 'utf8')
} catch (err) {
res.status(404).send('Page doesn\'t exist!')
}
try {
const convertedData = md.render(data)
await readFilePromise(path.join(__dirname, '/template.html'), 'utf8')
data = data.replace(/\{\{content\}\}/, convertedData)
res.send(data)
} catch (err) {
console.log(err)
}
})
app.listen(3000)
module.exports = app
I tried running the test again, but it still fails with a 404. I think my set up within app.test.js is wrong, but I'm not sure exactly what, as I've tried using the various set ups as the article. How would I fix this?
Separately, when I try going to a URL using the async/await style in app.js, I get a ReferenceError: data is not defined error, but I'm not sure how to define data in the async/await format.
I explained here how to set up app for the test environment: supertest not found error testing express endpoint
You did not mention how you set the database environment, make sure your database is not empty. Then make your get request. but just checking status for get request is not enough because if your db is empty you will still get 200.
const response = await request(app).get("/route").send().expect(200);
expect(response.body.length).toBeGreaterThan(0)
Better approach would be connect to a different database, post your data first and then check the response
const response = await request(app).get("/api/tickets").send().expect(200);
expect(response.body.length).toEqual(2); // if you post two items
Also before you every test make sure you start with empty database inside beforeEach()