current url is: http://localhost:3000/products/60e03e16229da058968f33c3
but i want to mask it as http://localhost:3000/products/product-1
This is the getStaticPaths code that i have (uses apollo client to fetch the data)
const GET_ALL_QUERY = gql`
{
products {
id
}
}
`;
export async function getStaticPaths() {
const paths = await client
.query({
query: GET_ALL_QUERY,
})
.then((data) => {
const productsData = data.data.products;
if (productsData.length) {
return productsData.map((res) => {
return { params: { id: res.id } };
});
}
})
.catch((err) => Promise.reject(new Error(err)));
return {
paths,
fallback: false,
};
}
export async function getStaticProps({ params }) {
try {
const res = await client.query({
query: GET_ONE_QUERY,
variables: { id: params.id },
});
return {
props: res.data.product,
};
} catch (err) {
throw new Error(err);
}
}
if i use
<Link href={`/products/${product_id}` as={`/products/${product_name}`}>
</Link>
it doesnt seem to work. it is looking for /product-1 page and returns page not found.
also in sever.js,
i have
const server = express();
server.get("/products/:id", (req, res) => {
const actualPage = "/products";
const queryParams = { id: req.params.id };
console.dir("req.params.id = " + JSON.stringify(req.params.id));
app.render(req, res, actualPage, queryParams);
});
suspecting if this could be affecting the dynamic path.
I am not able to figure out the solution. Searched extensively but all resources refer to using only the id. Is this possible in nextjs ?
Related
How to create nextjs getStaticPaths function using dynamic and nested paths (graphql)?
I don't know how I can create the function correctly... Can someone help me? I am using Wordpress headless with graphQL
export async function getStaticPaths() {
const GET_ALL_SLUGS = gql`
query getAllSlugs {
posts {
nodes {
slug
}
}
pages {
nodes {
slug
}
}
}
`;
const response = await client.query({
query: GET_ALL_SLUGS,
});
const categories = response?.data?.pages?.nodes;
const posts = response?.data?.posts?.nodes;
let paths = {
params: {
category: "",
post: "",
},
};
paths = categories.map(({ slug }) => {
return {
params: {
category: slug,
},
};
});
paths = posts.map(({ slug }) => {
return {
params: {
post: slug,
},
};
});
return {
paths,
fallback: false,
};
}
This is my server file.
In context I am not getting the request while my test is getting pass while test the required scenario.
export async function buildTestServer({
user,
headers,
roles,
}: {
user?: User;
headers?: { [key: string]: string };
roles?: Role;
}) {
const schema = await tq.buildSchema({
authChecker: AuthChecker,
validate: false,
resolvers: allResolvers(),
scalarsMap: [{ type: GraphQLScalarType, scalar: DateTimeResolver }],
});
const server = new ApolloServer({
schema,
context: async ({ req }) => {
const authHeader = headers?.authorization;
if (authHeader) {
const token = extractTokenFromAuthenticationHeader(authHeader);
try {
const user = await new UserPermissionsService(token).call();
return { req, user };
} catch {
return { req };
}
} else {
if (user) {
let capabilities: any = [];
if (roles) {
capabilities = roles.capabilities;
}
return {
req,
user: {
id: user.id,
customerId: user.customerId,
capabilities,
},
};
} else {
return { req };
}
}
},
});
return server;
}
And this is my test file from where I am sending the request to the server.
My test is getting passed but I am not getting the request headers. I want to check the the request. Can anybody help me out ?
const GET_LIST = `
query GetList($listId: String!) {
GetList(listId: $listId) {
id
}
}
`;
test('Get Lists', async () => {
const customer = await CustomerFactory.create();
const user = await UserFactory.create({ customerId: customer.id });
const list = await ListFactory.create({
customerId: customer.id,
});
const server = await buildTestServer({ user });
const result = await server.executeOperation({
query: GET_LIST,
variables: {
listId: list.id
},
});
var length = Object.keys(result.data?.GetList).length;
expect(length).toBeGreaterThan(0);
});
I am trying to update some value in my database using python and mongoose (mongo wrapper library). The value I am trying to update is contained in an array (filename).
Full method
module.exports.updateCampground = async (req, res) => {
const { id } = req.params;
const campground = await Campground.findByIdAndUpdate(id, { ...req.body.campground });
const imgs = req.files.map(f => ({ url: f.path, filename: f.filename }));
campground.images.push(...imgs);
await campground.save();
if (req.body.deleteImages) {
for (let filename of req.body.deleteImages) {
//logs cloudinary conataining uploader, still uploader is undefined
console.log(cloudinary,cloudinary.uploader);
await cloudinary.uploader.destroy(filename);
}
await campground.updateOne({ $pull: { images: { filename: { $in: req.body.deleteImages } } } })
}
req.flash('success', 'Successfully updated campground!');
res.redirect(`/campgrounds/${campground._id}`)
};
This works
const deleteImg = req.body.deleteImages
await campground.updateOne({ $pull: { images: { filename: { $in: deleteImg } } } })
and removes the item however when I do just this it doesn't
await campground.updateOne({ $pull: { images: { filename: { $in: req.body.deleteImages } } } })
Why do I need the const to work? Is it some javascript thing?
I'm using nuxtjs/axios and Mongoose to write to MongoDB. The POST always works but it takes a few seconds for the insert to get into MongoDB. Problem is that I'm trying to call a GET immediately after a new POST so i can get all the latest records. That doesn't always happen because it takes a few seconds for the data to get into the DB. Here's my index.js file for the server:
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config();
}
const Post = require('./models/post');
const express = require('express');
const { Nuxt, Builder } = require('nuxt');
const app = express();
const mongoose = require('mongoose');
const xss = require('xss-clean');
app.use(
express.urlencoded({
extended: true
})
)
app.use(express.json())
app.use(xss());
const config = require('../nuxt.config.js');
config.dev = process.env.NODE_ENV !== 'production';
const nuxt = new Nuxt(config);
const { host, port } = nuxt.options.server;
const username = process.env.username;
const pwd = process.env.pwd;
const server = process.env.server;
const db = process.env.db;
const dbURI = `mongodb+srv://${username}:${pwd}#${server}/${db}?
retryWrites=true&w=majority`;
async function start() {
if (config.dev) {
const builder = new Builder(nuxt);
await builder.build();
} else {
await nuxt.ready();
}
app.use(nuxt.render);
}
start();
mongoose
.connect(dbURI, {useNewUrlParser: true, useUnifiedTopology: true})
.then((result) => {
app.listen(port, host); // listen
}
)
.catch(err => console.log(err));
app.get('/posts', (req, res) => {
Post
.find()
.sort({createdAt: -1})
.then((result) => {
res.send(result);
})
.catch((err) => console.log(err));
})
app.post(
'/posts',
(req, res) => {
const post = new Post({
body: req.body.post.trim()
});
post
.save()
.then((result) => {
res.send(result);
})
.catch((err) => console.log(err));
}
);
I feel like in app.post the .save() isn't waiting for the insert to complete. Is my implementation wrong? Here's my Store:
export const actions = {
async getPosts() {
let res = await this.$axios.get(`/posts`);
return res;
}
}
export const mutations = {
async savePost(state, data) {
let res = await this.$axios.post('/posts', {post: data});
return res;
}
}
And here's my index.vue file:
export default {
components: {},
data: () => ({
posts:[],
confession: ""
}),
mounted(){
this.getPosts();
},
methods: {
async getPosts() {
let res = await this.$store.dispatch('getPosts');
this.posts = res;
},
async savePost(payload) {
let res = await this.$store.commit('savePost', payload);
return res;
},
clear(){
this.confession = "";
},
focusInput() {
this.$refs.confession.focus();
},
onSubmit() {
this
.savePost(this.confession.trim())
.then((result) => {
this.playSound();
this.getPosts();
this.clear();
this.focusInput();
});
},
playSound: function(){
// sound code
}
}
}
}
Maybe you can try to add w: "majority" option in save method.
Mongoose Documentation of save options
MongoDB Documentation for further explanation of 'writeConcern'
app.post(
'/posts',
(req, res) => {
const post = new Post({
body: req.body.post.trim()
});
post
.save({w: "majority"})
.then((result) => {
res.send(result);
})
.catch((err) => console.log(err));
}
);
I'm building my first CRUD app with NextJS/Mongodb and I'm using next-connect for the methods and I'm super new to all this.
I was able to successfully create a post, and update user profiles but I am completely stuck on deleting posts. I've tried to mimic the way I created posts but instead switch it to .deleteOne instead of .insertOne. I can also display post._id so I know that I can access it. I'm just confused on how to pass it into my delete function.
I understand that I should be passing in the post._id and then sending that to the handler.delete which lives in the api/ folder for NextJS then calling my delete function within the handler.delete. I've gone through multiple examples of using next-connect for CRUD operations but almost none of them demonstrate the delete operation. Or maybe I'm just looking in the wrong place. I've attached the code below for reference on where I currently am.
Any help would be appreciated. Thanks!
// components/post/posts.jsx
function Post({ post }) {
const postDelete = (id) => {
const body = {
_id: id,
};
fetch("/api/posts", {
method: "DELETE",
body: JSON.stringify(body),
});
};
return (
<div>
{post._id}
<button onClick={() => postDelete(post._id)}>Delete</button>
</div>
);
// api/posts/index.js
handler.delete(async (req, res) => {
console.log("reached handler delete function");
const deleteResult = await deletePost(req.db, {
_id: req.post._id,
});
return res.json({ deleteResult });
});
// db/posts.js
export async function deletePost(db, { _id }) {
return db.collection("posts").deleteOne({
_id,
});
}
replace
// api/posts/index.js
handler.delete(async (req, res) => {
console.log("reached handler delete function");
const deleteResult = await deletePost(req.db, {
_id: req.post._id,
});
return res.json({ deleteResult });
});
by
// api/posts/index.js
handler.delete(async (req, res) => {
console.log("reached handler delete function");
const deleteResult = await deletePost(req.db, req.body._id);
return res.json({ deleteResult });
});
Answer
The issue was my variable names.
// components/post/posts.jsx
const postDelete = async (event) => {
if (userInfo) {
const body = {
postId: post._id,
};
const res = await fetch("/api/posts/patch", {
method: "DELETE",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
if (res.status === 200) {
toast.success("Post Deleted!");
}
} else {
toast.error("Please sign-in!");
}
};
// api/posts/index.js
handler.delete(async (req, res) => {
console.log(req.body);
const del = await deletePost(req.db, {
postId: req.body.postId,
});
return res.status(200).send("Uploaded");
});
// db/posts.js
export async function deletePost(db, { postId }) {
return db
.collection("posts")
.deleteOne({
"_id": postId,
})
.then(({ value }) => value);
}