Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Next.js server actions and components 1st-class Sanctum citizens #58

Closed
wants to merge 8 commits into from
Prev Previous commit
Next Next commit
Update serverFetch with suggestions from @Willem-Jaap
jared-cannon committed Jan 19, 2025

Verified

This commit was signed with the committer’s verified signature.
snyk-bot Snyk bot
commit db5322b48c571f5122323cdc5caf3300daa72608
78 changes: 44 additions & 34 deletions src/lib/serverFetch.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,52 @@
'use server'

import {cookies} from 'next/headers'
const DEFAULT_HEADERS = {
'Content-Type': 'application/json',
Accept: 'application/json',
'X-Requested-With': 'XMLHttpRequest',
}

/**
* Forwards cookies from the client to the server, adds base URL, and adds additional headers.
*
* @param url
* @param options
* Forwards cookies from the client to the server if run on the server, adds base URL, and adds additional headers.
*/
export async function serverFetch(url, options = {}) {
export async function serverFetch(route, config = {}) {

const options = {
config: {
...config,
credentials: 'include',
cache: 'no-cache',
},
headers: {
...DEFAULT_HEADERS,
...(await getHeaders()),
...config.headers,
},
};

// Strip leading slash from route.
if (route.startsWith('/')) {
route = route.slice(1);
}

const cookieStore = await cookies();
return await fetch(`${process.env.NEXT_PUBLIC_BACKEND_URL}/${route}`, options);
}

const session = cookieStore.get(process.env.LARAVEL_SESSION_COOKIE_NAME || 'laravel_session')?.value;
const csrf = cookieStore.get(process.env.LARAVEL_CSRF_COOKIE_NAME || 'XSRF-TOKEN')?.value;
const getHeaders = async () => {
// 💡 If running on server, include the headers of the current request.
return typeof window === 'undefined' ? getServerHeaders() : {};
}

if (! session || ! csrf) {
// If either cookie is missing, return void. This should be handled by the useAuth hook on our client component.
return;
}
const getServerHeaders = async () => {
const { headers, cookies } = await import('next/headers');
const headerStore = await headers();
const Referer = headerStore.get('host');
const cookie = headerStore.get('cookie');

const headers = new Headers();
headers.append('X-Requested-With', 'XMLHttpRequest');
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
headers.append('X-XSRF-TOKEN', decodeURIComponent(csrf));
headers.append('Origin', process.env.NEXT_PUBLIC_FRONTEND_URL);

cookieStore.getAll().forEach(cookie => {
headers.append('Cookie', `${cookie.name}=${cookie.value}`);
});

const requestInit = {
method: options.method || 'GET',
headers,
body: options.body ? JSON.stringify(options.body) : null,
cache: 'no-cache',
}
const cookieStore = await cookies();
const csrf = cookieStore.get(process.env.LARAVEL_CSRF_COOKIE_NAME || 'XSRF-TOKEN')?.value;

return await fetch(process.env.NEXT_PUBLIC_BACKEND_URL + url, requestInit);
}
return {
...(Referer && { Referer }),
...(cookie && { cookie }),
...(csrf && { 'X-XSRF-TOKEN': decodeURIComponent(csrf) }),
};
};