Im new to a codebase where they use flow.
I dont understand this bit:
const {
headers: { location },
}: Response = await httpClient.post(getChangeServicesUrl(userId), newChangeService);
Can you please explain whats happening?
is it, destructuring location, and then whats the colon doing?
thanks
const {
headers: { location },
}: Response = await httpClient.post(...
Is equivalent to:
const response: Response = await httpClient.post(...
const location = response.headers.location;
So first part is object destructuring
const {
headers: { location },
}
And : Response is a type annotation
Related
I am trying to fetch products from shopify API but don't understand why it's throwing an an error set in my catch statement. The error says
error - utils/fetchShop.js (28:10) # productData
Error: Products not fetched
26 | return data;
27 | } catch (error) {
> 28 | throw new Error('Products not fetched');
| ^
29 | }
30 | }
Can you help me figure out what I am doing wrong here. So basically I am
Creating a function called productData that will accept a query.
productData it will make a POST request to the Shopify Storefront GraphQL API using the set headers and return the json response.
productData function will return the data to the getAllProducts function which will set it equal to the allProducts variable.
Here is my code:
const domain = process.env.SHOPIFY_STOREFRONT_DOMAIN;
const storefrontAccessToken = process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN;
async function productData(query) {
const URL = `https://${domain}/api/2022-04/graphql.json`;
const options = {
endpoint: URL,
method: 'POST',
headers: {
'X-Shopify-Storefront-Access-Token': storefrontAccessToken,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
query
}),
};
try {
const data = await fetch(URL, options).then((response) => {
return response.json();
});
return data;
} catch (error) {
throw new Error('Products not fetched');
}
}
export async function getAllProducts() {
const query = `{
products(first: 250) {
edges {
node {
handle
id
}
}
}
}`;
const response = await productData(query);
const slugs = response.data.products.edges ?
response.data.products.edges :
[];
return slugs;
}
So I had this exact problem. It seems to be something to do with the URL variable being all caps.
If you change:
const URL = `https://${domain}/api/2022-10/graphql.json`;
endpoint: URL
To:
const _url = `https://${domain}/api/2022-10/graphql.json`;
endpoint: _url
That should fix the problem. It worked for me.
Be sure to also change the variable in your fetch too to reflect the changes.
EDIT: As this variable is immutable I have added the underscore to note this.
Below my pages directory i have a few routes (for example "/product/details").
I'm using getServerSideProps() to have the page render server side.
How can i send a POST request containing data in the body to this page directly?
The idea would be that i can do something like this:
export async function getServerSideProps(postData) {
return {
props: {postData.body},
}
}
I've tried console logging "postData". I can see that the post request headers are being sent, but the request body is missing.
Thanks
Edit:
I'm doing the posting using Postman, and i'm sending a raw body of type JSON containing a single key:value. But as i said, the page doesn't seem to receive the posted data.
Here is a code snippet for how i'm sending a post request to a route using puppeteer:
const page = await puppeteerConnection.newPage();
await page.setRequestInterception(true);
await page.once('request', (request) => {
let data = {
'method': 'POST',
'postData': JSON.stringify(jsonData),
'headers': {
...request.headers(),
'Content-Type': 'application/json'
},
};
request.continue(data);
page.setRequestInterception(false);
});
await page.goto('pathToNextJSRoute');
getServerSideProps() accepts a context parameter (which you've named postData in your example) and one of the keys in that object (req) contains the request body you're looking for. It arrives as a readable stream of byte data, though, so you'll need to convert it first:
const streamToString = async (stream) => {
if (stream) {
const chunks = [];
for await (const chunk of stream) {
chunks.push(Buffer.from(chunk));
}
return Buffer.concat(chunks).toString("utf-8");
}
return null;
};
export async function getServerSideProps(context) {
let data = null;
if (context.req.method === "POST") {
const body = await streamToString(context.req);
data = JSON.parse(body);
}
console.log(data);
return {
props: { data },
};
}
i am trying to fetch some data from an api using getStaticProps with next js. It returns the error undefinedcannot be serialized as JSON. Please usenull` or omit this value.
I have amended the code based on the solutions proposed online about the topic but none of them work.
export async function getStaticProps() {
const propertyForSale = await fetchApi(`${baseUrl}/properties/list?locationExternalIDs=5002&purpose=for-sale&hitsPerPage=6`);
const propertyForRent = await fetchApi(`${baseUrl}/properties/list?locationExternalIDs=5002&purpose=for-rent&hitsPerPage=6`);
return {
props: {
// Initial code
propertyForSale: propertyForSale?.hits,
propertyForRent: propertyForRent?.hits,
// the below snippet fixes the issue but return null
// propertyForSale: propertyForSale?.hits ?? null,
//propertyForRent: propertyForRent?.hits ?? null,
//the below snippet fixes the issue but return Unexpected token u in JSON at position 0
// propertyForSale: JSON.stringify(JSON.parse(propertyForSale?.hits))
//propertyForRent: JSON.stringify(JSON.parse(propertyForRent?.hits)),
}
}
}
fetchapi.js
export const baseUrl = 'https://bayut.p.rapidapi.com'
export const fetchApi = async (url) => {
const {result} = await axios.get((url), {
headers: {
'x-rapidapi-host': 'bayut.p.rapidapi.com',
'x-rapidapi-key': process.env.NEXT_PUBLIC_BAYU_API
},
});
console.log(result);
return result;
};
As Lazar pointed out in his comment, in your question's code snippet, you're trying to destructure a property that doesn't exist. And since axios returns an object with the data property, you're only left with destructuring the correct property:
const { data } = await axios.get(.....)
or...
const result = await axios.get(.....);
return result.data;
if you insist on the result thing :D
To fix the error I renamed constant result to data as per below.
I am not sure of what is the reason of this bug, if someone wanna add something to explain the reason why naming the constant data fixed the bug be my guess.
export const fetchApi = async (url) => {
const {data} = await axios.get((url), {
headers: {
'x-rapidapi-host': 'bayut.p.rapidapi.com',
'x-rapidapi-key': process.env.NEXT_PUBLIC_BAYU_API
},
});
return data;
};
export async function getStaticProps() {
const propertyForSale = await fetchApi(`${baseUrl}/properties/list?locationExternalIDs=5002&purpose=for-sale&hitsPerPage=6`);
const propertyForRent = await fetchApi(`${baseUrl}/properties/list?locationExternalIDs=5002&purpose=for-rent&hitsPerPage=6`);
return {
props: {
// Initial code
propertyForSale: propertyForSale?.hits,
propertyForRent: propertyForRent?.hits,
}
}
}
can you try this please?
return {
props: {
propertyForSale: propertyForSale?.hits || null,
propertyForRent: propertyForRent?.hits || null,
}
}
I am using react query as stated in the doc
But, I am not sure how to return {notFound: true} from getServerSideProps. Could anyone help me how to handle this?
My code ins getServerSideProps is:
const queryClient = new QueryClient();
await queryClient.prefetchQuery('amenities', () => getAmenities(params?.id as string));
return {
props: {
dehydratedState: dehydrate(queryClient),
},
};
Now, what I want to do is, if the response is 404, then return 404 from getServerSideProps.
Update: I was not able to find any solution so removed react query in getServerSideProps. Now I'm fetching the data normally.
what you can do is do it on the client side.
const { data, isLoading, isError } = useQuery(
["amenities", router.query.id],
() => getAmenities(router.query.id)
)
if(isError) router.push('404');
You can do it in the server side too
const queryClient = new QueryClient();
const data = await queryClient.prefetchQuery('amenities', () => getAmenities(params?.id as string));
if (!data) {
return {
notFound: true,
}
}
return {
props: {
dehydratedState: dehydrate(queryClient),
},
};
I have a question about auth0 and next js.
For example, I have the next code (this code works)
//initialprops enables server-side rendering in a page and allows you to do initial data population
ModelsList.getInitialProps = async (ctx) => {
//this is static token to test from auth0.com
const accessToken = 'eyJhbG.....'
//fetching data
const res = await fetch('http://localhost:7071/api/bo/getModels', {
headers: {
Authorization: `Bearer ${accessToken}`
}
})
const json = await res.json()
return { data: json }
}
As you can see, I have accessToken variable as a text. It's a problem for me
How can make accessToken dynamic?
Thanks a lot!
P.S please, dont reference to auth0 documentation, I have tried a lot. Provide, please, a real solution/example.
Ok, so this is what worked for me.
Let's say you've got api.example.com/resources. This where data actually is. You will need to proxy via next's api.
Inside your jsx component, you fetch next's api.
// components/Dashboard.jsx
const API_URL = "api/resources";
async function fetcher(url: any) {
const res = await fetch(url);
const json = await res.json();
return json;
}
function Dashboard() {
const { data, error } = useSWR(API_URL, fetcher);
if (error) return <div>failed to load</div>;
if (!data) return <div>loading...</div>;
return <div>show your resources here</div>;
}
and now inside the next's api file you can fetch the actual endpoint you need.
// api/resources.js
import {
getAccessToken,
getSession,
withApiAuthRequired,
} from "#auth0/nextjs-auth0";
export default withApiAuthRequired(async function healthcheck(req, res) {
const session = await getSession(req, res);
const token = session?.idToken;
const response = await fetch("https://api.example.com/resources", {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
},
});
const data = await response.json();
res.status(200).json(data);
});
if you get errors, check the jwts you're getting. Audience or scope mismatch errors are usually the main culprits.