Is there any way to fetch data within the next.config.js file, I am trying to set up i18n but would like for the locales array to be fetched from a CMS rather than statically input by the developer.
From Next.js docs: (https://nextjs.org/docs/api-reference/next.config.js/introduction)
next.config.js is a regular Node.js module, not a JSON file. It gets used by the Next.js server and build phases, and it's not included in the browser build.
It means that you can do something like this:
module.exports = {
async headers() {
const response = await fetch("https://example.com/langs");
const dt = await response.json();
return [
{
source: "/api/dashboard",
headers: [{ key: "Lang", value: dt.map((d) => d.lng).join(",") }],
},
];
},
};
Obviously the above code can be done inside the endpoint handler but I just wanted to give an example to prove it's working.
Related
I have an api "https://www.pinkvilla.com/photo-gallery-feed-page/page/1" which returns response something like this.
"nodes": [
{
"node": {
"title": "PHOTOS: Shruti Haasan's Turkey vacay- A perfect mix of work and fun",
"nid_dont_use": "1",
"field_photo_image_section": "/files/styles/photogallery/public/shruti_haasan_in_turkey_main_0.jpeg?itok=ex_mE-AH",
"path": "/photos/shruti-haasan/photos-shruti-haasans-turkey-vacay-perfect-mix-work-and-fun-1184120",
"nid": "1184120",
"photo_image_nids": "1184114,1184115,1184116,1184117,1184118,1184119",
"ImageStyle_thumbnail": "/files/styles/imagestyle_1_1/public/shruti_haasan_in_turkey_main_0.jpeg?itok=44jwEbFY",
"last_update": "1661754431",
"views_count": "305",
"author_uid": "870656",
"author_name": "Pinkvilla Desk"
}
},
I am trying to get images from this api and I see two objects which have image path in it.
"ImageStyle_thumbnail": "/files/styles/imagestyle_1_1/public/shruti_haasan_in_turkey_main_0.jpeg?itok=44jwEbFY"
"field_photo_image_section": "/files/styles/photogallery/public/shruti_haasan_in_turkey_main_0.jpeg?itok=ex_mE-AH",
Is there any way I can get images from this api?
It seems like the pictures you're searching for can be composed by adding your API image url's to pinkvilla base url: https://www.pinkvilla.com/files/styles/photogallery/public/shruti_haasan_in_turkey_main_0.jpeg?itok=ex_mE-AH
You could try composing pinkvilla's base url with paths returned from your API, but it won't be a failsafe approach, as you can't possibly know if those images actually exists on pinkvilla's webserver.
You could do something like this to get the image URLs:
const [imageUrls, setImageUrls] = useState();
const fetchImages = async () => {
const baseUrl = "https://www.pinkvilla.com";
const result = await fetch(`${baseUrl}/photo-gallery-feed-page/page/1`).then((res) => res.json());
setImageUrls(result.nodes.map((node) => `${baseUrl}${node.node.field_photo_image_section}`));
};
fetchImages();
And then can use that array of URLs (imageUrl) to render the images using the <img src=""/> tag.
Looking up several examples online, it appears all one would need to do to redirect requests to the backend is to add rewrites to the next.config.js file, and it should work. However, I must be missing or misunderstanding something as this alone doesn't seem to do the trick. Redirecting seems to work if I type the url in the browser, but calls from axios/fetch continue to try to use a path relative to my client. Here are my snippets:
next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/api',
destination: 'http://localhost:3001',
},
]
},
};
components/MyComponent.js
import React, { useEffect } from "react";
import axios from "axios";
function MyComponent({projectName}) {
...
useEffect(() => {
axios.get("/api/project/" + projectName)
.then((res) => {
console.log(res);
});
return;
}, []);
...
};
export default MyComponent;
To clarify, if I hit http://localhost:8001/api/project/Name_of_Project from the browser, I get properly redirected to my server (hosted on port 3001) and receive data I'd expect. However, when I hit my client (http://localhost:8001/Name_of_Project), axios doesn't redirect and tries http://localhost:8001/api/project/Name_of_Project which obviously fails. I also tried the fetch equivalent instead of axios and get the same result.
Is there another step that I need to take? Does the rewrite not work for axios/fetch? I have also seen mentions of the next-http-proxy-middleware package in my search, but I am not sure if this is something that I need to use in conjunction with the rewrite or not.
I appreciate any insight!
EDIT 1:
After doing some more searching, I ran into this post, and discovered that my issue is because I am using relative pathing in my axios call. If I change it to:
axios.get("http://localhost:3001/api/project/" + projectName)
.then((res) => {
console.log(res);
});
then I get my data properly. I suppose this leads me to my next question: is there a way to use relative path alongside the rewrite in the config? I personally think it's a little ugly to have the hostname and port exposed like that (I eventually plan on hosting this app on a FQDN). So if there's anything that can be done about that, I'd love to know!
EDIT 2: Of course the change in my first edit works because I am hitting my server directly! Which is not the desired effect. I want to use the redirect set in the config to go to my api.
Aha! I WAS misunderstanding something. I assumed that the path in the rewrite would reattached my path params for free. This is not the case. A link to the documentation.
The relevant excerpt:
Wildcard Path Matching
To match a wildcard path you can use * after a parameter, for example /blog/:slug* will match /blog/a/b/c/d/hello-world:
module.exports = {
async rewrites() {
return [
{
source: '/blog/:slug*',
destination: '/news/:slug*', // Matched parameters can be used in the destination
},
]
},
}
So my corrected next.config.js:
module.exports = {
async rewrites() {
return [
{
source: '/api/:slug*',
destination: 'http://localhost:3001/api/:slug*',
},
]
},
};
I'm working on an e-commerce app built on NextJS and Sanity, so far I've made some mock products with all the necessary requirements, a user login system and checkout. I've been trying to make an invoice system so that when the user confirms an order 3 things must happen:
send all the order data to a react-pdf component and generate the invoice(working)
post the invoice file to the sanity schema so that the user has access to it when he goes to his order history page(not working)
email both the company and the client about the order(not implemented yet but I can do it)
ReactPDF allows me to access the pdf through a hook that returns me the blob of the file and the URL. I've tried to POST both of them but the url returned 404 and the blob didn't upload at all.
Searched the docs of both ReactPDF and Sanity and I couldn't find anything, although I think it has to do something with this endpoint from Sanity:
myProjectId.api.sanity.io/v2021-06-07/assets/files/myDataset
This is how I POST the order to my sanity studio
const { data } = await axios.post(
'/api/orders',
{
user: userInfo,
invoice_id: orders.length + 1,
orderItems: cartItems.map((item) => ({
...item,
slug: undefined
})),
billingData,
paymentMethod,
itemsPrice,
taxPrice,
totalPrice
},
{
headers: {
authorization: `Bearer ${userInfo.token}`
}
}
);
I've tried making 2 POST requests, one for the invoice_file alone, trying to post the blob or the url but none did work. The schema for invoice file was updated for the type of post each time so I'm 99% sure that wasn't the issue, anyway here's how the schema for invoice_file looks as for file:
{
name: 'invoice_file',
title: 'Invoice',
type: 'file',
options: {
storeOriginalFilename: true
}
},
If there would be any other code snippets relevant please let me know.
I really don't know how to find the solution for this as it's the first time trying to do such thing, so help would be much appreciated.
Thanks in advance!
I apologies as I'm not really active here but it's hard to pass on your question especially as I'm working on something similar. There's probably other ways to do this but I suggest you work use the official Sanity client. There's a specific section in the README that tells us how to do the file uploads or here.
So here's kinda the very small snippet:
import {
Document,
pdf,
} from "#react-pdf/renderer";
const doc = <Document />;
const asPdf = pdf([]); // {} is important, throws without an argument
asPdf.updateContainer(doc);
const blob = await asPdf.toBlob();
// `blob` here is coming from your react-pdf blob
const fileName = "customfilename.pdf";
client.assets.upload("file", blob, { filename: fileName }).then((fileAsset) => {
console.log(fileAsset", fileAsset);
// you can then use the fileAsset to set and reference the file that we just uploaded to our document
client.patch("document-id-here").set({
invoice_file: {
_type: "file",
asset: {
_type: "reference",
_ref: fileAsset._id,
},
},
}).commit();
});
So i'm trying to send image files uploaded by my users to firebase storage using the file type input element. Like this:
<input
className={inputStyle}
{...register("donorPhotoFile")}
type="file"
accept=".png, .jpg,.jpeg"
></input>
So when I try to console.log the value returned of that input, im getting an object with the following properties:
name: "file_name.jpg",
size: ,
type: "image/png"
webkitRelativePath: ""
The /api/firebase is my api endpoint in next.js to upload my form data to firestore. From the firebase documentation, the 'file' should come from File API which I've did but its always unsuccessful and im not sure what im doing wrong.
const submitForm = async (data) => {
const imageFile = data.donorPhotoFile[0] //this is the file
const imageUpload = await fetch("/api/firestorage", {
method: "POST",
body: imageFile
});
const res = await imageUpload.json()
console.log(res)
}
//in my firestorage endpoint i've done this:
const storage = getStrorage(app) //app here is an instance of my firebase initialized
const handler = async (req, res) => {
const storageRef= ref(storage)
const imageFile = req.body
try {
uploadBytes(storageRef, imageFile);
res.status(200).json({statusRes: "success"})
} catch(error) {
res.status(400).json({statusRes: "failed", errorMessage: error})
}
}
Doing that returns a storage/invalid-root-operation error code with a message of:
"Firebase Storage: The operation 'uploadBytes' cannot be performed on a root reference, create a non-root reference using child, such as .child('file.png')
So tried to make a reference to a specific file and inserted the file name as a second parameter to storageRef like this:
const storageRef = ref(storage).child(`images/${req.body.name}`)
but its still not working but now i'm getting an empty error object so I can't figure out what's wrong now. So i actually tried checking what req.body is and it's returning this:
file object in my api endpoint
I don't understand why is it like that? And what im actually looking at? What i've sent in my post request is a File object. Like this:
File object i attached to my post request
You can create a reference to a path using Modular SDK as shown below:
const storageRef= ref(storage, `images/${req.body.name}`)
The .child() method is used in older name-spaced syntax.
So I have never post a data using FormData and multipart/form-data as Content-Type in my React project. But now I'm kinda forced by backend to send it this way since we have some images in payload.
The problem is that the whole data is a JS object and can be parsed to JSON, and nothing more. So how can I convert my JS object into a valid FormData that backend would accept it? Everything works without a problem in Postman, but in the app I always get the same error.
Here is some more detail:
The working Postman sample:
What I expect to be working (but obviously doesn't):
const createProd = () =>
HttpRequest.post('/api/prod', {
body: {
Product: {
title: 'Test Prod',
shop: null,
description: "My new ad's description",
category: { id: '5d8c6aa6fadeaf26b0194667' },
condition: 'USED'
}
});
HttpRequest is a helper function which uses ES6 fetch for requests.
I always get the same error: "Required request part 'Product' is not present" with/without JSON.stringify.
I even tried to create a sample FormData to at least change the error:
cont payload = new FormData();
payload.append('Product', {foo: 'bar'});
But still same error. I also copied the code which is generated by Postman. But still no chance.
I would be thankful if you share your suggestions or workarounds.
Thanks in advance.
const formData = new FormData();
const product = { //your product object };
formData.append('product', JSON.stringify(product));
const config = {
headers: {
'Content-Type': 'multipart/form-data; charset=utf-8; boundary="another cool boundary";'
}
};
axios.post(`/api/ads`, formData, config).then((res) => {
console.log(res);
}).catch(err => {
console.log(err);
});
Maybe you should set header.
Try this one. In my case I used Axios. It worked for me in my project.