Axios vs Fetch in Nextjs
Answered
Asiatic Lion posted this in #help-forum
Asiatic LionOP
what is better to use in nextjs for api calls, axios or fetch ?
152 Replies
@Asiatic Lion what is better to use in nextjs for api calls, axios or fetch ?
fetch. Axios was popular a time ago...
Yea, that what joulev linked
@Asiatic Lion solved?
Asiatic LionOP
i can see many opinions
some with fetch and some with axios
@Asiatic Lion some with fetch and some with axios
With Next.js, fetch api works the best!
Asiatic LionOP
hmm
Red-necked Grebe
fetch, nextjs fetch is at different level...
Asiatic LionOP
but its too annoying to work with
Asiatic LionOP
im using fetch
export async function resetPassword(data: ResetPasswordModel) {
const response = await fetch(`${SERVER_URL}/accounts/reset-password`, {
method: "POST",
headers: {
"Content-Type": "text/plain",
"auth_token": data.token,
},
body: JSON.stringify({
newPassword: data.password
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || `HTTP error! status: ${response.status}`);
}
return await response.json();
}even if i put application/json its working in a very annoying behavior
its including all the data in the body, and including the token in the query params
why
Asiatic LionOP
is it because of my request url ?
@Asiatic Lion is it because of my request url ?
Red-necked Grebe
better wrote it like this to handle advance error and if no avail you can return default/null then log the error
const response = await fetch(`${SERVER_URL}/accounts/reset-password`, {
method: "POST",
headers: {
"Content-Type": "text/plain",
"auth_token": data.token,
},
body: JSON.stringify({
newPassword: data.password
}),
}).then(res=>{
if(res.status!==200){
// handle?
}
// maybe validate json?
return res.json()
}).catch(()=>{
//handle error here
});Asiatic LionOP
the problem what because im using it in "use server" file
when i moved it to the component where im calling it, it worked
Red-necked Grebe
hm? it should work on "use server" file if it's imported
Asiatic LionOP
its working
but the behavior not as expected
Red-necked Grebe
which?
you have throw there, it would break the code without try-catch.
or then.catch
Asiatic LionOP
the case is its causing including all the payload inside the body
while im just assigning one field
and the other issue, is that its including the token that is in the url param inside the request param
Red-necked Grebe
${SERVER_URL}/accounts/reset-password?auth_token=${token} like this?also notes, if you call fetch from use server file, it will call from inside the runtime,
if it's on use client it will call from browser
if it's on use client it will call from browser
Asiatic LionOP
yea
i mean when i call it from inside the use server
it includes all the payload and the token without even assigng it
@Asiatic Lion it includes all the payload and the token without even assigng it
Red-necked Grebe
into the body?
Asiatic LionOP
thats the unexpected behavior
into the body + inside the query string parameters
// here the query string parameters
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImthbWVsbmFzc2FyMjgyOEBnbWFpbC5jb20iLCJpYXQiOjE3MTYzNzE0MTMsImV4cCI6MTcxNjM3NTAxM30.NGWd_9IUTShhQJx9BF4NWk4Jjt5qZwobh7pJ9CNWJsk
// here the payload
[,…]
0
:
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImthbWVsbmFzc2FyMjgyOEBnbWFpbC5jb20iLCJpYXQiOjE3MTYzNzE0MTMsImV4cCI6MTcxNjM3NTAxM30.NGWd_9IUTShhQJx9BF4NWk4Jjt5qZwobh7pJ9CNWJsk"
1
:
"kamel123"
// here the query string parameters
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImthbWVsbmFzc2FyMjgyOEBnbWFpbC5jb20iLCJpYXQiOjE3MTYzNzE0MTMsImV4cCI6MTcxNjM3NTAxM30.NGWd_9IUTShhQJx9BF4NWk4Jjt5qZwobh7pJ9CNWJsk
// here the payload
[,…]
0
:
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImthbWVsbmFzc2FyMjgyOEBnbWFpbC5jb20iLCJpYXQiOjE3MTYzNzE0MTMsImV4cCI6MTcxNjM3NTAxM30.NGWd_9IUTShhQJx9BF4NWk4Jjt5qZwobh7pJ9CNWJsk"
1
:
"kamel123"
Red-necked Grebe
those are request or response(?)
Asiatic LionOP
request
in the network tab, inside the payload
Red-necked Grebe
how do you know request body? logging from backend?
try change to
application/json
from text/plain
Asiatic LionOP
export async function resetPassword(data: ResetPasswordModel) {
const response = await fetch(`${SERVER_URL}/accounts/reset-password/`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"auth_token": data.token
},
body: JSON.stringify({ newPassword: data.password }),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || `HTTP error! status: ${response.status}`);
}
return await response.json();
}this is the function
Red-necked Grebe
are you using server action?
you might be mixing and confuse request owner, those request is looks like server action request
Asiatic LionOP
im using it on submit inside a form
Red-necked Grebe
if there is like
0: blablabla
1: blablabla
this is came from server action/use transition
0: blablabla
1: blablabla
this is came from server action/use transition
any codes from your form would be helpful
Asiatic LionOP
const {
register,
handleSubmit,
formState: {
errors,
isSubmitting,
isSubmitted,
isSubmitSuccessful = isSubmitted && errors.root === undefined
},
setError
} = useForm<ResetPasswordModel>({
resolver: zodResolver(ResetPasswordSchema),
});
const handleResetPassword = async (data: ResetPasswordModel) => {
try {
await resetPassword(data);
}catch (error: any) {
console.log(error.message, 'error.message,')
setError("root", { message: error.message });
}
}
<form onSubmit={handleSubmit(handleResetPassword)}>
....
</form>this is inside a "use client"
Red-necked Grebe
most likely came from this
Asiatic LionOP
where ?
Red-necked Grebe
the way you handle the form
Asiatic LionOP
but in other forms its working in a normal way
what u suggest ?
Red-necked Grebe
i suggest to breakdown by consol logging from up to bottom, to find unusual data before hitting the fetch
the fetch itself has nothing wrong
it seems ok
@Asiatic Lion into the body + inside the query string parameters
// here the query string parameters
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImthbWVsbmFzc2FyMjgyOEBnbWFpbC5jb20iLCJpYXQiOjE3MTYzNzE0MTMsImV4cCI6MTcxNjM3NTAxM30.NGWd_9IUTShhQJx9BF4NWk4Jjt5qZwobh7pJ9CNWJsk
// here the payload
[,…]
0
:
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImthbWVsbmFzc2FyMjgyOEBnbWFpbC5jb20iLCJpYXQiOjE3MTYzNzE0MTMsImV4cCI6MTcxNjM3NTAxM30.NGWd_9IUTShhQJx9BF4NWk4Jjt5qZwobh7pJ9CNWJsk"
1
:
"kamel123"
Red-necked Grebe
also this payload is typical server action payload...
you might be unconsciously triggering server action
Asiatic LionOP
after the debugging, i foudn that the cause is from my page
this is my page url
when i copied the token and putted it manually inside the fetch function
it worked as expcted
Red-necked Grebe
i see
Asiatic LionOP
but that the url will be like this
http://localhost:3000/reset-password
http://localhost:3000/reset-password
Red-necked Grebe
you need to get the queryParams first
Asiatic LionOP
its because the url
Red-necked Grebe
then pass it into your function
Asiatic LionOP
im passing it and getting it
Red-necked Grebe
it might lost in the middle
try console logging right before you call the fetch
does the data includes your param?
if no, there must be something wrong with how you get the query
either it is not passed correctly
or you wrongly put the token somewhere else
Asiatic LionOP
GET /reset-password?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImthbWVsbmFzc2FyMjgyOEBnbWFpbC5jb20iLCJpYXQiOjE3MTYzNzU0OTcsImV4cCI6MTcxNjM3OTA5N30.51wPQXzi301f1dZpZvatgZ4ISlNgrtHF--YG8y0GKow 200 in 91ms
{
password: 'kamel123',
confirmPassword: 'kamel123',
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImthbWVsbmFzc2FyMjgyOEBnbWFpbC5jb20iLCJpYXQiOjE3MTYzNzU0OTcsImV4cCI6MTcxNjM3OTA5N30.51wPQXzi301f1dZpZvatgZ4ISlNgrtHF--YG8y0GKow'
} dataaaaa
{
password: 'kamel123',
confirmPassword: 'kamel123',
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImthbWVsbmFzc2FyMjgyOEBnbWFpbC5jb20iLCJpYXQiOjE3MTYzNzU0OTcsImV4cCI6MTcxNjM3OTA5N30.51wPQXzi301f1dZpZvatgZ4ISlNgrtHF--YG8y0GKow'
} dataaaaa
Red-necked Grebe
on your body there is no confirmPassword
that might be the problem
Asiatic LionOP
this is the request payload
{
"password": "kamel123",
"confirmPassword": "kamel123",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImthbWVsbmFzc2FyMjgyOEBnbWFpbC5jb20iLCJpYXQiOjE3MTYzNzU0OTcsImV4cCI6MTcxNjM3OTA5N30.51wPQXzi301f1dZpZvatgZ4ISlNgrtHF--YG8y0GKow"
}
{
"password": "kamel123",
"confirmPassword": "kamel123",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImthbWVsbmFzc2FyMjgyOEBnbWFpbC5jb20iLCJpYXQiOjE3MTYzNzU0OTcsImV4cCI6MTcxNjM3OTA5N30.51wPQXzi301f1dZpZvatgZ4ISlNgrtHF--YG8y0GKow"
}
Red-necked Grebe
unused confirmPassword?
on the fetch?
Asiatic LionOP
export async function resetPassword(data: ResetPasswordModel) {
console.log(data, 'dataaaaa')
const response = await fetch(`${SERVER_URL}/accounts/reset-password/`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"auth_token": data.token
},
body: JSON.stringify({ newPassword: data.password }),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || `HTTP error! status: ${response.status}`);
}
return await response.json();
}im not including it in the body, why is it there
Red-necked Grebe
oh i see
let me explain
takes a while
Asiatic LionOP
also im taking the token from the headers like this
import {ResetPassword} from "@/app/components/forms/auth/ResetPassword";
export default function ResetPasswordPage({searchParams} : { [key: string]: string | string[] | undefined }) {
return (
<ResetPassword token={searchParams.token} />
);
}inside the (auth)/reset-password/page.tsx
there is not problem to provide a token like this http://localhost:3000/reset-password?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im in my current folder structure ?
Red-necked Grebe
const {
register,
handleSubmit,
formState: {
errors,
isSubmitting,
isSubmitted,
isSubmitSuccessful = isSubmitted && errors.root === undefined
},
setError
} = useForm<ResetPasswordModel>({
resolver: zodResolver(ResetPasswordSchema),
});
const handleResetPassword = async (data: ResetPasswordModel) => {
// ^^^^^^^^ this actually called from the server based
// on your request which includes
// 0: [something, something, etc] << remember this
//
try {
await resetPassword(data);
// ^^^^ this run on server-side which
// console.log on server-side and client are different
// if you want to update the state or get response
// you should return it
}catch (error: any) {
console.log(error.message, 'error.message,')
setError("root", { message: error.message });
}
}
<form onSubmit={handleSubmit(handleResetPassword)}>
....
</form>then the data goes to
export async function resetPassword(data: ResetPasswordModel) {
// data.token and data.password are confirmed to be exist
const response = await fetch(`${SERVER_URL}/accounts/reset-password/`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"auth_token": data.token
},
body: JSON.stringify({ newPassword: data.password }),
});
// ^^^^^^^^^ this request are CANNOT BE SEEN from your browser
// this might be you got confuse about there is no return payload.
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || `HTTP error! status: ${response.status}`);
}
return await response.json(); // << you return here but not above as i said above
}might need to change a bit like...
or prefferably use
const handleResetPassword = (data: ResetPasswordModel, callback:any) => {
(async(){
try {
const result = await resetPassword(data);
callback(result)
}catch (error: any) {
console.log(error.message, 'error.message,')
setError("root", { message: error.message });
// ^^ if this client function it cannot be called!!!
}
})()
}or prefferably use
useTransition()maybe here is the problem also ?
@Asiatic Lion is this valid ?
Red-necked Grebe
not a problem from code point of view
Asiatic LionOP
this is how its sent from the backend
@Red-necked Grebe might need to change a bit like...
typescript
const handleResetPassword = (data: ResetPasswordModel, callback:any) => {
(async(){
try {
const result = await resetPassword(data);
callback(result)
}catch (error: any) {
console.log(error.message, 'error.message,')
setError("root", { message: error.message });
// ^^ if this client function it cannot be called!!!
}
})()
}
or prefferably use `useTransition()`
Red-necked Grebe
if this not working, try to use
useTransition() methodyou have more control over the request and response
Asiatic LionOP
how to use transition
Red-necked Grebe
try to read on this docs
https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations
https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations
or just make the fetch client side lmao
Asiatic LionOP
haha
i think its the best way
Red-necked Grebe
i do use server action, but i rarely use <form> with it
here is my example code
Asiatic LionOP
im using the nextjs, as a frontend, there is a separate backend server, when im making api requests, im putting the requests on a folder called _api and in the head of it im putting "use server" is this structure fine ?
Red-necked Grebe
import { useTransition, useState } from 'react'
import { SomeApiCall } from 'somewhere' // << "use server" function
function ElementExample(){
const [pending, transit] = useTransition()
const [data, setData] = useState({
token: null,
password: null
})
const handleClick = () => {
if(pending) return;
transit(async()=>{
const result = await SomeApiCall(data)
// handle on client.
})
}
return (
<div onClick={handleCliek}></div>
)
}@Asiatic Lion im using the nextjs, as a frontend, there is a separate backend server, when im making api requests, im putting the requests on a folder called _api and in the head of it im putting "use server" is this structure fine ?
Red-necked Grebe
you must plan your fetch on the client or server of a nextjs XD
Asiatic LionOP
i cant make both ?
Red-necked Grebe
you can
just make sure you wont mixmatch them
Asiatic LionOP
so make one folder called api for the api that will use the "use server" and one _api that will be called inside the cliend
right ?
is this fine as code structure ?
Red-necked Grebe
_api << this will be ignored btw
because
_ is marked as private folderin nextjs
the code wont make it into public
Asiatic LionOP
the thing is that the docs is like for the nextjs projects that will not use a custom backend
Red-necked Grebe
i do use custom backend
[next-client] -> [next-server] ---> [rust backend]
Asiatic LionOP
oh well
so how to devide my apis, one that will run on server and one to run on clinet
each in folder ?
one ServerApi, and one ClientApi
Red-necked Grebe
i personally use this guideline
Asiatic LionOP
the api is outside the app dir?
Red-necked Grebe
yes because Next Action is enough to call it
because it's private api (endpoint not exposed)
then from /src/api ---> forward to rust backend
i do use flow like this
Asiatic LionOP
but ur making inside the api dir a file called feature.[detail].ts ?
like this ?
Red-necked Grebe
like
those file is calling to rust backend using fetch
/api
- user.login.ts
- user.data.ts those file is calling to rust backend using fetch
Asiatic LionOP
can i push my code and u just organize it ?
so i can continue
its really taugh
headaches
its stills at initial level
Red-necked Grebe
i would like to help, but might be 1 or 2 example only, the rest you can follow
Asiatic LionOP
yea sure
just i want a restructure
and i can follow at all
Red-necked Grebe
let's move to PM right? this is public XD
for sensitive detail such as sharing email/github repo
Asiatic LionOP
haha right
Red-necked Grebe
case solved ☕
Answer