How to get the query params inside getServerSideProps in nextjs - reactjs

My URL is something like this:
http://localhost:3000/success?merchant=xxxxxx&order_id=xxxxx&payment_ref_id=xxxxxxx&status=Aborted&status_code=9999&message=Not%20a%20Nagad%20account
I need to get the payment_ref_id from the URL inside getServerSideProps. How can I do that?
I tried something like context.query.payment_ref_id but didn't work.
My code :
export const getServerSideProps: GetServerSideProps = async (context) => {
try {
const payment_reference_id = context.query.payment_ref_id;
const response = await axios.get(`${BASE_URL}/remote-payment-gateway-1.0/api/dfs/verify/payment/${payment_reference_id}`,
{
headers: {
"X-KM-IP-V4": IP_ADDRESS,
"X-KM-Client-Type": "PC_WEB",
"X-KM-Api-Version": "v-0.2.0",
"Content-Type": "application/json",
}
});
const payment_verify_res = await response.data;
const paymentStatus = await payment_verify_res.status;
return {
props: {
StatusProps: payment_verify_res || null,
PaymentStatus: paymentStatus || null,
},
}
} catch (error) {
console.log(error);
return { props: {} }
}
}

This might sound silly, but check if you have this code in /pages/success.tsx or /pages/success/index.tsx
Also after getting the response you are not calling the data() method.
Your code should probably look something like this :
const payment_verify_res = await response.data();
const paymentStatus = payment_verify_res.status;

Related

How do I assign a value from response to body for another post data?

so I have 2 post data functions, the first is to upload photo/file, another one is for add a document.
in the API for add document, there are 3 body that need to be filled. name(string), location(string), and photo(string).
I already created the function for upload photo, and I get the return link of the url path for photo.
My question is, how do I assign the link from url path to body add document for photo(string)?
json for add document :
json for uploaded photo:
code for upload photo:
try {
const postFileReq = await axios.post(
"https://spda-api.onrender.com/api/file/upload",
formData,
options
);
const postFileRes = await postFileReq.data.image;
if (postFileReq.status === 200) {
setPhotoUrl(postFileRes);
console.log("postFileRes", postFileRes);
// console.log("photoUrl", photoUrl);
}
} catch (error) {
const err = error as AxiosError;
console.log(err.response?.data);
}
code for add document:
try {
const postDocReq = await axios.post(
"https://spda-api.onrender.com/api/admin/documents",
{
name: field.name,
location: field.location,
photo: photoUrl,
},
{
headers: {
"Content-Type": "application/json",
authorization: `Bearer ${token}`,
},
}
);
const postDocRes = await postDocReq.data;
if (postDocReq.status === 200) {
setShowSnackbar(true);
router.reload();
console.log(postDocRes);
}
} catch (error) {
const err = error as AxiosError;
console.log(err.response?.data);
}
i already tried using useState to assign but it still not working, anyone have an idea?
const [photoUrl, setPhotoUrl] = useState("");
My complete code: https://pastebin.com/Rb5xX08z
Alright so what you need you to do is call the second api in the success method of the first call. I will jump to the code directly with async/await. You can do it with then as well.
You can handle it inside your if condition 200 success. So like once it is successfull call the second function then. But I have shown with async/await like mentioned
import axios from 'axios'
const MyComponent = () => {
const [data, setData] = useState(null);
const [secondData, setSecondData] = useState(null);
const fetchData = async () => {
try {
const response = await axios.get('https://first-api.com');
setData(response.data);
//if first api was successful,call the second api
const secondResponse = await axios.get(`https://second-api.com/${response.data.id}`);
setSecondData(secondResponse.data);
} catch (error) {
console.error(error);
}
};
useEffect(() => {
fetchData();
}, []);
return (
<div>
<p>Data from first API: {JSON.stringify(data)}</p>
<p>Data from second API: {JSON.stringify(secondData)}</p>
</div>
);
};

What do I put in my return if I want to return the response from an api call react?

I needed to add headers to my api call. I tried doing this many different ways to no avail. This is my original api call without the header:
export default async function FetchPageMarkdown(page: string): Promise<string> {
const baseUrl = getBackendUrl();
let response = await fetch(`${baseUrl}/api/pagemarkdown/${page}`);
let text = await response.text();
return text
}
This is how I am trying to add the header:
const FetchPageMarkdown = (page: string): Promise<string> => {
const { getAccessTokenSilently } = useAuth0();
const callSecureApi = async () => {
const token = await getAccessTokenSilently();
const baseUrl = getBackendUrl();
const response = await fetch(
`${baseUrl}/api/pagemarkdown/${page}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
const text = await response.text();
return text;
}
};
export default FetchPageMarkdown;
Without having a return I get a function whose declared type is neither 'void' nore 'any' must return a value. I want to return the text coming from the api call which is markdown. If I put the return outside the callSecureApi function it cannot find text.
Have you tried calling and returning the result of the asynchronous function, i.e. return callSecureApi();?
Since useAuth0 is a React hook it can't be called from functions (breaks rules of hooks), but its getAccessTokenSilently function can be passed around.
const fetchPageMarkdown = (getAccessTokenSilently: () => string, page: string): Promise<string> => {
const callSecureApi = async () => {
const token = await getAccessTokenSilently();
const baseUrl = getBackendUrl();
const response = await fetch(
`${baseUrl}/api/pagemarkdown/${page}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
const text = await response.text();
return text;
}
return callSecureApi(); // invoke and return Promise
};
Usage:
const { getAccessTokenSilently } = useAuth0();
fetchPageMarkdown(getAccessTokenSilently, page)
.then(text => {
// handle returned text
});

How to fetch API data from Axios inside the getServerSideProps function in NextJS?

I'm building an App with Next.js, and I need to connect to specific API routes (set up with API Platform) and populate pages with the route's responses.
The API is working fine, but no matter how I try to implement my Axios call inside the getServerSideProps, I always get the same error, ECONNREFUSED, from my Node stack.
I tried to get the data from useEffect() and it's working fine, but I would like to know if there's a way to call it directly in getServerSideProps.
I'm using a Node container for Docker, and the routes are authenticated through a JWT Token (stored in the session and the client cookies for the server-side connection)
Here are is my code:
pages/accounts.js:
export async function getServerSideProps(context) {
const cookies = new Cookies(context.req.headers.cookie)
const adminToken = cookies.get('jwtToken')
const res = await getAllAccounts(adminToken)
return {
props: {
testdata: ''
},
}
}
lib/accounts.js:
import service from '../service'
export const getAllAccounts = async (adminToken) => {
const res = service({ jwtToken : adminToken }).get(`/accounts`).then((response) => {
}).catch((error) => {
console.dir(error)
})
}
HTTP wrapper:
import axios from 'axios';
import jwt_decode from "jwt-decode";
import mockAdapter from 'axios-mock-adapter';
const service = ({ jwtToken = null, store = null, mockURL = null, mockResponse = null, multipart = false } = {}) => {
const options = {};
options.baseURL = process.env.NEXT_PUBLIC_API_URL + '/api';
if(multipart === true) {
options.headers = {
'Content-Type': 'multipart/form-data'
}
} else {
options.headers = {
'Content-Type': 'application/ld+json',
accept: 'application/ld+json'
}
}
const instance = axios.create(options);
instance.interceptors.response.use(response => {
return response;
}, error => {
return Promise.reject(error);
})
if (mockURL !== null && mockResponse !== null) {
let mock = new mockAdapter(instance);
mock.onAny(mockURL).reply(200, mockResponse)
}
return instance;
};
export default service;
Through the error dump in the node stack, I managed to see that the request headers are correct, and the JWT correctly passed through.
Do not use Axios. Just use fetch().
Next.js polyfills fetch() by default on both the client and server, so you can just use it:
In addition to fetch() on the client-side, Next.js polyfills fetch() in the Node.js environment. You can use fetch() in your server code (such as getStaticProps/getServerSideProps) without using polyfills such as isomorphic-unfetch or node-fetch.
Source.
getServerSideProps works well with axios if we return response.data
export const getServerSideProps: GetStaticProps = async ({ params }) => {
const { brandName } = params as IParams;
const brandData = await $host.get(`api/brand/${brandName}`).then(response => response.data);
return {
props: {
brand: brandData,
},
};
};
Your problem is that your async method does not return a promise.
import service from '../service'
export const getAllAccounts = async (adminToken) => {
const res = service({ jwtToken : adminToken }).get(`/accounts`);
return res;
}
In my NextJS begining I followed this tutorial , and I changed fetch to axios in this way:
export const getStaticPaths = async () => {
const res = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await res.json();
const paths = data.map((ninja) => {
return {
params: { id: ninja.id.toString() },
};
});
return {
paths,
fallback: false,
};
};
export const getStaticProps = async (context) => {
const id = context.params.id;
const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
const data = await res.json();
return {
props: { ninja: data },
};
};
I applied the change using useEffect()
useEffect(() => {
// const data = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
// const res = await data.json();
// setninja(res);
const fetchData = async () => {
const result = await axios(`https://jsonplaceholder.typicode.com/users/${id}`);
setninja(result.data);
};
fetchData();
console.log(data);
}, []);
I hope this info will be useful for you.
I Used Axios in getServerSideProps without any problems.
export const getServerSideProps: GetServerSideProps = async({
params,
res
}) => {
try {
const response = await axios.get(`/api/test`);
return {
props: {
data: response.data
},
}
} catch {
res.statusCode = 404;
return {
props: {}
};
}
};

Not able to get values from the api to chart.js, react js

so this is my api, which is stored in a url
"https://covid19.mathdro.id/api/confirmed"
this is my api index file
import axios from "axios";
const url = "https://covid19.mathdro.id/api/confirmed";
export const fetchData = async () => {
try {
const {
data: countryRegion ,
} = await axios.get(url);
return { countryRegion };
} catch (error) {
return error;
}
};
in this sandbox code, i have tried to take the value of countryRegion from the api, but it appears as undefied in the console.
https://codesandbox.io/s/react-chartjs-2-nqo9n
Looks like you are destructuring incorrectly.
const { data: { countryRegion } } = await axios.get(changeableUrl);
Do this in your api
const { data: countryRegion } = await axios.get(changeableUrl);
Update based on the comment:
If only country is needed in the array, just map thru it and extract countryRegion
export const fetchData = async country => {
try {
let { data: countryRegion } = await axios.get(url);
return { countryRegion: countryRegion.map(country => country.countryRegion) };
} catch (error) {
return error;
}
};

How to set route params for CRUD application using Redux and API server

I'm working on a React/Redux application that needs to make a simple GET request to an API server endpoint (/contents/{id}). Right now I have an action set up to fetch this data:
export const fetchInfoPage = id => {
return async dispatch => {
try {
const res = await fetch(`${server}/contents/${id}`)
if (res.ok) {
const json = await res.json()
await dispatch(fetchPageRequest())
await setTimeout(() => {
dispatch(fetchPageSuccess(json.data))
}, 1000)
} else {
const json = await res.json()
console.log(res, json)
}
} catch (error) {
dispatch(fetchPageFailure(error))
console.log(error)
}
}
}
And here's what fetchPageSuccess looks like:
const fetchPageSuccess = content => {
const { id, attributes } = content
return {
type: FETCH_PAGE_SUCCESS,
isFetching: false,
id: id,
name: attributes.name,
content: attributes.content,
created_by: attributes.created_by,
updated_by: attributes.updated_by,
created_at: attributes.created_at,
updated_at: attributes.updated_at
}
}
I am firing off this action inside of componentDidMount in my InfoPage component by using fetchInfoPage(match.params.name). The match.params.name is set up to match the parameters in the React Route (i.e. /:name/information). I want to instead change this to fetch the data by using an ID number from the JSON while still displaying :name as the route parameter.
I feel like I'm close in getting this wired up but there's a gap in my logic somewhere. Is it possible to do what I'm trying to do here? I also have access to a GET endpoint at /contents/slug/{slug}.
It's perfectly fine what you are trying to do.
Just map the id using your name in the fetchInfoPage from your json or you can actually send the id to your fetchInfoPage function from component. It has nothing to do with your route params. All you are doing is getting the name from your param and getting the corresponding id using your name. I assume you have a name: id map somewhere.
export const fetchInfoPage = name => {
return async dispatch => {
try {
const id = getIdFromName(name); // Write a helper function
const res = await fetch(`${server}/contents/${id}`)
if (res.ok) {
const json = await res.json()
await dispatch(fetchPageRequest())
await setTimeout(() => {
dispatch(fetchPageSuccess(json.data))
}, 1000)
} else {
const json = await res.json()
console.log(res, json)
}
} catch (error) {
dispatch(fetchPageFailure(error))
console.log(error)
}
}
}
Your route will still be /:name/information
What I ended up doing was fetching by slug instead. On the components where I fetched the data, I created the slug name in componentDidMount by using match.params.name from my route, then fired off fetchInfoPage(slugName) to get the data. I also cleaned up the code quite a bit so here's what fetchInfoPage looks like now:
export const fetchInfoPage = slug => {
return async dispatch => {
try {
dispatch(fetchPageRequest())
const res = await fetch(`${server}/contents/slug/${slug}`)
const contentType = res.headers.get('content-type')
if (contentType && contentType.includes('application/vnd.api+json')) {
const json = await res.json()
if (res.ok) {
dispatch(fetchPageSuccess(json))
} else {
printError(res, json)
dispatch(fetchPageFailure(res.body))
dispatch(push('/error'))
}
} else {
console.log('Not valid JSON')
dispatch(fetchPageFailure(res.body))
dispatch(push('/error'))
}
} catch (error) {
dispatch(fetchPageFailure(error))
dispatch(push('/error'))
console.log(`Network error: ${error.message}`)
}
}
}
And a componentDidMount example:
componentDidMount() {
const { match, fetchInfoPage } = this.props
const slugName = `${NAMESPACE}-${match.params.name}`
fetchInfoPage(slugName)
}

Resources