Using nextjs, I have state that contains the users JWT, This needs to be passed into the request in getServerSideProps.
export async function getServerSideProps(ctx) {
const res = await fetch('http://localhost:1337/publics')
const data = await res.json()
const theData = data[ctx.query.id - 1]
return {
props: {data: theData},
}
}
How can i pass the JWT here?
Related
I started learning Remix and got to a point where I would like to get some data from APIs. I created a loader function, in routes folder (initially I did this in component, which is wrong), where I fetch my API call:
export async function loader() {
const res = await fetch("https://reqres.in/api/users?page=2");
return json(await res.json());
}
After that I used the data in my component, where needed:
const { data } = useLoaderData();
Now I would like to use another API, but I don't know how properly to do that in the loader function
export async function loader() {
const res = await fetch("https://reqres.in/api/users?page=2");
// second API i would like to use but don't know how :(
const faqRes = await fetch("https://jsonplaceholder.typicode.com/posts");
return json(await res.json());
}
How could I use multiple APIs in Remix?
You can return more data:
export async function loader() {
const res = await fetch("https://reqres.in/api/users?page=2");
const faqRes = await fetch("https://jsonplaceholder.typicode.com/posts");
return json({
res: await res.json(),
faqRes: await faqRes.json()
});
}
Then in your component:
const { res, faqRes } = useLoaderData();
What if you want to wait for 1st API data and pass the response to 2nd API?
e.g.
export async function loader() {
const res = await fetch("https://reqres.in/api/users?page=2");
const faqRes = await fetch(`https://jsonplaceholder.typicode.com/posts/${res.userId}`);
return json({
faqRes: await faqRes.json()
});
}
This question already has an answer here:
How to access route parameter inside getServerSideProps in Next.js?
(1 answer)
Closed 10 months ago.
I have getServerSideProps function to get data from API:
export async function getServerSideProps() {
const res = await fetch(
`https://www.thecocktaildb.com/api/json/v1/1/search.php?s=${queryCocktailName}`
)
const data = await res.json()
return {
props: { data },
}
}
I need to get query in this function, ( /search/queryCocktailName/ ) i tried const {query} = useRouter() but as NextJS say: Hooks can only be called inside of the body of a function component
This component location: search/[id].tsx
This should work:
import { GetServerSidePropsContext } from "next";
export async function getServerSideProps({
params
}: GetServerSidePropsContext<{ id: string }>) {
const res = await fetch(
`https://www.thecocktaildb.com/api/json/v1/1/search.php?s=${params?.id}`
);
const data = await res.json();
return {
props: { data }
};
}
See docs. getServerSideProps gets context object as a first parameter and it contains params field which should contain an id field, because your file is named [id].tsx.
Edit: changed to TypeScript version.
Every getServerSideProps have context, which comprises of req and res.
export async function getServerSideProps({req, res}) {
const { url = "" } = req || {};
//url will have the query of your route like :: url = /search/queryCocktailName/
const res = await fetch(
`https://www.thecocktaildb.com/api/json/v1/1/search.php?s=${queryCocktailName}`
)
const data = await res.json()
return {
props: { data },
}
}
Above code will work for your use-case
In the fisrt part I ma suign fetch() and it is working fine but whe i use useSWR() it returns UNDEFINED
export const getAllEvents = async()=>{
const response = await fetch('https://*******-rtdb.firebaseio.com/events.json');
const data = await response.json();
const events = [];
for (const key in data){
events.push({
id:key,
...data[key]
});
}
return events; // returns data as I wanted.. perfect
}
but in the following snippet it returns undefined (the same url)
import useSWR from 'swr';
const {data, error} = useSWR('https://*******-rtdb.firebaseio.com/events.json');
console.log(data); // returns undefined
useSWR expects fetcher function as second argument:
https://swr.vercel.app/#overview
It can be a custom method e.g.
export const fetcher = async (...args: Parameters<typeof fetch>) => {
const res = await fetch(...args);
if (!res.ok) {
throw { status: res.status, statusText: res.statusText };
}
return res.json();
};
Use swr also needs to take a fetcher function, right now you're just passing down a url. Swr doesnt know what to do with that url..
const { data, error } = useSWR(
"https://api.github.com/repos/vercel/swr",
fetcher
);
const fetcher = (url) => fetch(url).then((res) => res.json());
I suggest you read the docs.
add this :
const fetcher = (...args) => fetch(...args).then(res => res.json())
const {data, error} = useSWR('https://*******-rtdb.firebaseio.com/events.json', fetcher);
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: {}
};
}
};
I'm using next.js and the import { useRouter } from 'next/router'.
However on initial load, router.query.id is undefined. It quickly fills in, but that initial load is a killer.
I'm trying to figure out how to do it, and tried:
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
// const res = await fetch(`https://.../posts/${params.id}`)
// const post = await res.json()
console.log(params)
// Pass post data to the page via props
return { props: { params } }
}
but this returns an error:
Error: getStaticPaths is required for dynamic SSG pages and is missing for '/app/d/[id]'.
I can't use getStaticPaths, since [id] is variable and can be any number of things.
So what's the best way to handle this?
I would do smt like this(without staticProps):
function Page(props) {
const router = useRouter();
const { query = {} } = router || {};
const { id = 0 } = query || {};
useEffect(()=> {
if(id) {
(async ()=> {
const res = await fetch(`https://.../posts/${id}`)
const post = await res.json();
})();
}
}, [id]);
}
And this is what official doc. says:
// You also have to define a Post component in the same file (pages/posts/[id].js)
function Post({ post }) {
const router = useRouter()
// If the page is not yet generated, this will be displayed
// initially until getStaticProps() finishes running
if (router.isFallback) {
return <div>Loading...</div>
}
return <h1>Posts are here</h1>;
}
// This also gets called at build time
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
// Pass post data to the page via props
return { props: { post } }
}
UPDATE:
After a bit research, have figure out this solution with staticProps:
export default function Post({ post }) {
return <h1>Post is here</h1>;
}
export async function getStaticPaths() {
return {
paths: [
{ params: { id: '*' } }
],
fallback: true
};
}
export async function getStaticProps(context) {
const res = await fetch(`https://api.icndb.com/jokes/random/${context.params.id}`);
const post = await res.json()
return { props: { post } }
}