NextJS 13 fails to fetch from internal api route when deploying - mongodb

When fetching from /api in npm run dev or npm run build/start my code is working, but when try to deploy it on Vercel it fails to fetch. Im using Next js 13 with app dir.
here is my code on the client (server component)
`const getAvailableSlots = async () => {
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/api/availabilityList`
);
if (!res.ok) {
console.log(res);
}
return res.json();
};
const Appointments = async () => {
const data = await getAvailableSlots();
return (
<div className="App">
<div>
<AppointmentsPage data={data} />
</div>
</div>
);
};
export default Appointments;`
and this is the /api route:
`const handler = async (req, res) => {
await connectDB();
console.log("Connected to Mongo");
try {
const availiblityList = await Users.find();
res.status(200).send(availiblityList);
} catch (error) {
res.status(400).send(error.message);
}
};
export default handler;`
I tried directly accessing the data from the server since its server components, but in development mode it loads on the first time with warning that only can pass down simple object as props and can't reload after that.
`import { getData } from "../../pages/api/availabilityList";
const getAvailableSlots = async () => {
const res = await getData();
return res;
};
const Appointments = async () => {
const data = await getAvailableSlots();
console.log(data);
return (
<div className="App">
<div className="section section0 fp-auto-height-responsive items-center">
<AppointmentsPage data={data} />
</div>
</div>
);
};
export default Appointments;`
/api
`export async function getData() {
await connectDB();
const response = await Users.find();
return response;
}
const handler = async (req, res) => {
const jsonData = await getData();
res.status(200).json(jsonData);
};
export default handler;`
The Warning:
Warning: Only plain objects can be passed to Client Components from Server Components. Objects with toJSON methods are not supported. Convert it manually to a simple value before passing it to props. [{$__: ..., $isNew: false, _doc: ...}, ...]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Related

Propagate live updates return promise object instead of value

Working on beginner steps toward vue 3 and firestore migration. Stuck on simple.
import { getUsersCount } from "/src/firebase";
setup() {
const usersCount = getUsersCount();
return {
usersCount,
};
},
Why it returns Promise Object, I cant find in manuals.
export const getUsersCount = async () => {
// const querySnap = await getDocs(query(collection(db, "users")));
const q = query(collection(db, "users"));
const unsub = onSnapshot(q, (querySnapshot) => {
console.log("usersCount33: ", querySnapshot.size);
//unsub();
return querySnapshot.size;
});
}
Nad the last part with template,
<template>
<p>Users Count: {{ usersCount }}</p>
</template>
If you return the value inside a callback, you can not use async await syntax. You should do this:
export const getUsersCount = () => {
return new Promise((resolve, reject) => {
const q = query(collection(db, "users"));
const unsub = onSnapshot(q, (querySnapshot) => {
return resolve(querySnapshot.size)
});
})
}
// You still need to wait getUsersCount when using it
const usersCount = await getUsersCount();

Getting db.close is not a function in sample JEST

I'm trying to setup testing my node with mongo app using Jest. I've set it up and copied their sample verbatim, which works fine, except when I call the db.close(); function. It gives me a TypeError: that db.close is not a function. This is directly out of their example:
import { MongoClient } from 'mongodb';
describe('insert', () => {
let connection;
let db;
beforeAll(async () => {
connection = await MongoClient.connect(global.__MONGO_URI__, {
useNewUrlParser: true,
});
db = await connection.db(global.__MONGO_DB_NAME__);
});
afterAll(async () => {
await connection.close();
await db.close();
});
it('should insert a doc into collection', async () => {
const users = db.collection('users');
const mockUser = {_id: 'some-user-id', name: 'John'};
await users.insertOne(mockUser);
const insertedUser = await users.findOne({_id: 'some-user-id'});
expect(insertedUser).toEqual(mockUser);
});
});

Nexjs + SWR: API resolved without sending a response for /api/projects/<slug>, this may result in stalled requests

Since on first render I was not able to get the router.query I am passing the params from getServerSideProps as follows:
export async function getServerSideProps(context) {
return {
props: { params: context.params },
};
}
Then in the function am trying to do the API call but am getting the API stalled error
API resolved without sending a response for
/api/projects/nichole_robel23, this may result in stalled requests.
This is my code:
export default function Project({ params }) {
const { slug } = params;
let [projectData, setProjectData] = useState([]);
let [loading, setLoading] = useState(true);
const { data } = useSWR('http://localhost:3000/api/projects/' + slug);
useEffect(() => {
if (data) {
setProjectData(data.data.project);
setLoading(false);
}
}, [data]);
......
I have global SWRCofig as follows
<SWRConfig value={{ fetcher: (url) => axios(url).then(r => r.data) }}>
<Layout>
<Component {...pageProps} />
</Layout>
</SWRConfig>
Any way to solve the problem?
You are missing your fetcher–the function that accepts the key of SWR and returns the data, so the API is not being called.
You are also not returning a response correctly from the API–this is most likely a case of not waiting for a promise/async to be fulfilled correctly.
CLIENT
const fetcher = (...args) => fetch(...args).then((res) => res.json());
export default function Home({ params }) {
const { slug } = params;
const [projectData, setProjectData] = useState([]);
const [loading, setLoading] = useState(true);
const { data } = useSWR(`http://localhost:3000/api/projects/${slug}`, fetcher);
useEffect(() => {
if (data) {
setProjectData(data);
setLoading(false);
}
}, [data]);
API
const getData = () => {
return new Promise((resolve, reject) => {
// simulate delay
setTimeout(() => {
return resolve([{ name: 'luke' }, { name: 'darth' }]);
}, 2000);
});
}
export default async (req, res) => {
// below will result in: API resolved without sending a response for /api/projects/vader, this may result in stalled requests
// getData()
// .then((data) => {
// res.status(200).json(data);
// });
// better
const data = await getData();
res.status(200).json(data);
}

getstaticprops cannot use params from getstaticpaths in case of dynamic routing? MongoDB

I am making a webpage which fetches data from mongoDB( atlas BASIC free plan) and has dynamic routing page with SSG. The dynamic routing page, [cogid].js, has getstaticpaths and getstaticprops. getstaticpaths seems work, but getstaticprops does not work. I guess the problem is variable "params.cogid" inside getstaticprops...
import { MongoClient } from "mongodb";
const { MONGODB_URI, MONGODB_DB } = process.env;
export default function Cog({ cogData }) {
return (
<div className="container mx-auto px-2 my-5 flex flex-col ">
<p>COG ID: COG{cogData.cog_id}</p>
<p>name: {cogData.name}</p>
</div>
);
}
export async function getStaticPaths() {
const client = new MongoClient(MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
if (!client.isConnected()) await client.connect();
const res = await client
.db(MONGODB_DB)
.collection("test1")
.find({})
.project({ cog_id: 1, _id: 0 })
.toArray();
if (client.isConnected()) client.close();
const paths = res.map((copiedCog) => ({
params: { cogid: copiedCog.cog_id },
}));
return { paths, fallback: false };
}
export async function getStaticProps({ params }) {
const client = new MongoClient(MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
if (!client.isConnected()) await client.connect();
const resp = await client
.db(MONGODB_DB)
.collection("test1")
.findOne({ cog_id: params.cogid });
if (client.isConnected()) client.close();
const cogData = await JSON.parse(JSON.stringify(resp));
return { props: { cogData } };
}
I solved the problem.
I should have changed the data type of params.cogid to Integer (from String?) like Number(params.cogid) or parseInt(params.cogid). It is because the type of the field "cog_id" of the DB is Integer.

Error when combining Express Router with Massive.js db call

When making an async/await call to database from an express router to postgres db via massive.js instance, the correct response from db is received, but the router apparently returns before async function finishes; therefore, the test invocation returns undefined. From the console out (below), it seems clear that the async function is not waited for >_<
Is wrapping the router in order to pass the app instance causing the issue?
app.js
const app = express();
const massiveInstance = require("./db_connect");
const routes = require("./routes");
const PORT = 3001;
const server = massiveInstance.then(db => {
// Add db into our app object
app.set("db", db);
app.use("/api", routes(app));
app.listen(PORT, () => {
console.log("Server listening on " + PORT);
});
});
routes.js
const router = require("express").Router();
const { countRegions } = require("./db_queries");
const routes = app => {
const db = app.get("db");
router.get("/regions/count", async (request, response) => {
try {
const total = await countRegions(db);
console.log(`There are ${total} regions.`);
response.send(`There are ${total} regions.`);
} catch (err) {
console.error(err);
}
});
return router;
};
module.exports = routes;
db_queries.js
const countRegions = db => {
db.regions.count().then(total => {
console.log(`db has ${total} count for regions`);
return total;
});
};
module.exports = {
countRegions,
};
console output
Server listening on 3001
There are undefined regions.
db has 15 count for regions
You are not returning a promise returned by then in countRegions method.
So you should add return in your code like this
const countRegions = db => {
//here
return db.regions.count().then(total => {
console.log(`db has ${total} count for regions`);
return total;
});
};
or simply do,
return db.regions.count();