I’m new to Next js and I’m a bit lost regarding the fetch data to an external API.
I basically want to fetch data (GET, POST, PUT, whatever), and add some pieces of logic that I don’t wish to rewrite every time I call an endpoint: in my case it’s adding the authorization token to the header for each request.
I used to do this with axios in a basic react project thanks to middleware or addAsyncRequestTransform
function.
I already have an external REST API done by a backend dev.
In my current project, I fetch users in my Users server component:
// page.tsx file
export default async function Users() {
const users = await fetchUsers();
return (
<UserTable data={users} />
);
}
I’m using server actions to fetch my users:
// admin.action.ts file
const endpoint = '/admin';
export async function fetchUsers() {
return await fetchWrapper<User[]>(endpoint + '/accounts');
}
and I have a fetchWrapper function to add my authorization token and other options to the header if necessary
// fetchWrapper.ts
import { notFound } from 'next/navigation';
interface FetchOptions extends RequestInit {
headers?: HeadersInit;
}
export interface ErrorData {
code: number;
status: string;
message: string;
}
// Define a generic FetchWrapper type
type FetchWrapper = <T>(url: string, options?: FetchOptions) => Promise<T>;
const fetchWrapper: FetchWrapper = async <T>(
url: string,
options: FetchOptions = {}
): Promise<T> => {
const token = "<my-hardcoded-token>";
const defaultHeaders: HeadersInit = {
'Content-Type': 'application/json',
};
if (token) {
defaultHeaders['Authorization'] = `Bearer ${token}`;
}
const baseUrl = process.env.NEXT_PUBLIC_API_BASE_URL as string;
const response = await fetch(`${baseUrl}${url}`, {
...options,
headers: {
...defaultHeaders,
...options.headers,
},
});
if (!response.ok) {
const errorData = (await response.json()) as ErrorData;
if (errorData.code === 404) notFound();
throw new Error(`Error ${response.status}: ${errorData.message}`);
}
return response.json() as Promise<T>;
};
export default fetchWrapper;
First of all, I’m not even sure that I should be using a GET
to fetch my users with a server-action even though it seems to be working.
Next js documentation says:
Behind the scenes, actions use the POST method, and only this HTTP method can invoke them.
In a second place, I can’t useSession
from next-auth to get the token in my fetchWrapper
function to add it for each request. So for not it’s hardcoded token that I need to replace manually every time.
I tried to explore the middleware
option in order to add the authorization header to my requests, but I ran into a problem:
// middleware.ts
export function middleware(request: NextRequest) {
console.log('???? ~ request >>', request);
}
when I log the request in the middleware I can see that the nextUrl is http://localhost:4000/users
instead of being the url of my external API.
I also read about the route handlers, but since i’m using an external api I don’t really see the point of using these.
Am I missing something ? Is middleware not designed to call external API ? Should I keep my current way of fetching data and find a way to pass the token every time ?