I want to test marvel api endpoints that needs environment variables in Next.js but I get this error:
Error: ❌ Attempted to access a server-side environment variable on the client.
getHash src/services/api.ts:7:23
5| const getTimestamp = () => Date.now().toString();
6| const getHash = (timeStamp: string) =>
7| md5(timeStamp + env.MARVEL_API_PRIVATE_KEY + env.MARVEL_API_PUBLIC_KEY);
This is my env file:
import { createEnv } from '@t3-oss/env-nextjs';
import { z } from 'zod';
export const env = createEnv({
server: {
NODE_ENV: z.enum(['development', 'test', 'production']),
MARVEL_API_PRIVATE_KEY: z.string(),
MARVEL_API_PUBLIC_KEY: z.string(),
MARVEL_API_URL: z.string().url(),
PORT: z.coerce.number().default(3000),
},
client: {},
runtimeEnv: {
NODE_ENV: process.env.NODE_ENV,
MARVEL_API_URL: process.env.MARVEL_API_URL,
MARVEL_API_PUBLIC_KEY: process.env.MARVEL_API_PUBLIC_KEY,
MARVEL_API_PRIVATE_KEY: process.env.MARVEL_API_PRIVATE_KEY,
PORT: process.env.PORT,
},
});
The service api function:
import md5 from 'md5';
import { env } from '@/env';
const getTimestamp = () => Date.now().toString();
const getHash = (timeStamp: string) =>
md5(timeStamp + env.MARVEL_API_PRIVATE_KEY + env.MARVEL_API_PUBLIC_KEY);
const timeStamp = getTimestamp();
const hash = getHash(timeStamp);
const query = `ts=${timeStamp}&apikey=${env.MARVEL_API_PUBLIC_KEY}&hash=${hash}`;
export const getCharacters = async () => {
const url = `${env.MARVEL_API_URL}/characters?limit=50&${query}`;
const response = await fetch(url);
const data = response.json();
return data;
};
The component where this function is called:
import { CharacterCard } from '@/app/components/Characters';
import { env } from '@/env';
import { Character } from '@/models/character';
import { getCharacters } from '@/services/api';
import styles from './styles.module.css';
export const CharactersList = async () => {
const characters = await getCharacters();
console.log(
'ENV',
env.NODE_ENV,
env.MARVEL_API_URL,
env.MARVEL_API_PRIVATE_KEY,
env.MARVEL_API_PUBLIC_KEY,
);
return (
<section className={styles.charactersList}>
{characters.data.results.map((character: Character) => (
<CharacterCard key={character.id} character={character} />
))}
</section>
);
};
While running the application in localhost the env variables are printed in the console but don't understand why not in the testing api call.
And the msw handler:
import { HttpResponse, http } from 'msw';
export const handlers = [
http.get('/characters', () => {
return HttpResponse.json(
{
id: 1011334,
name: '3-D Man',
},
{ status: 200 },
);
}),
];
You've not posted what is setup in your @/env dir, but at a guess I'd say you're not loading them properly.
You would typically have, and NextJS supports, having a
.envfile or.env.localin the root of your project (so not in any special dir). This is then automatically loaded intoprocess.envfor you to import.So, you'd likely need to remove what you've got in your @/env dir (or just make it a .env file in the root of the project).
And then set it up:
And then you would reference them like:
Additionally, and it may not be relevant here. But in NextJS to expose an env var publically, you need to prepend
NEXT_PUBLICso if you did want to useMARVEL_API_PUBLIC_KEYclient side you would need to make itNEXT_PUBLIC_MARVEL_API_PUBLIC_KEYNextJS has docs here, including some useful stuff about referencing other vars inside your
.env*files