I have my login method with nodejs and expressjs. How can I show my error response as a message in my nextjs component?
exports.login = asyncHandler(async(req, res, next) => {
const { email, password } = req.body;
if(!email || !password){
return res.status(400).json({ errors: [{ msg: 'Please enter all fields' }] });
}
//Check if user exists
let user = await User.findOne({ where: { email: email }});
if(!user){
return res.status(404).json({ errors: [{ msg: 'User not found' }] });
}
const isMatch = await user.matchPassword(password);
if(!isMatch){
return res.status(401).json({ errors: [{ msg: 'Invalid credentials' }] })
}
this.sendTokenResponse(user, 200, res);
})
For evey issue I return a response with a statuscode and a msg.
I want to access this response from my nextjs app when an error occurs while loggin in.
auth.service.ts
import { HttpAPI } from "../common/http.service";
export class AuthService {
static async login(email: string, password: string, onUserLoaded: (user: any) => void) {
try {
const response = await HttpAPI.post('http://localhost:3000/api/v1/auth/login', { email, password });
localStorage.setItem('access-token', response.token);
const userResponse = await HttpAPI.get('http://localhost:3000/api/v1/auth/me', {
headers: {
'Authorization': `Bearer ${response.token}`
}
});
onUserLoaded(userResponse.data);
document.cookie = "authenticated=true; path=/";
console.log("Respondiendo con error")
return response;
} catch (err) {
throw new Error(err.response.data.errors[0].msg);
}
}
static async getUserProfile(token: string) {
try {
const response = await HttpAPI.get('http://localhost:3000/api/v1/auth/me', {
headers: {
'Authorization': `Bearer ${token}`
}
});
return response.data;
} catch (error) {
throw new Error('Error al obtener el perfil del usuario');
}
}
static async logout(){
localStorage.removeItem('access-token');
function deleteCookie(name: string) {
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
}
deleteCookie('authenticated');
}
}
authContext.tsx
"use client"
import { AuthService } from "@/services/auth/auth.service";
import { UserType } from "@/types/user.types";
import { getAuthToken } from "@/utils/getAuthToken";
import { useEffect, useState, createContext, FC, PropsWithChildren, useContext } from "react";
export type AuthState = {
authToken: string | null;
user: UserType | null;
authError: string | null;
login: (email: string, password: string) => Promise<void>;
logout: () => void;
}
export const AuthContext = createContext<AuthState | undefined>(undefined);
export const AuthProvider: FC<PropsWithChildren> = ({ children}: PropsWithChildren) => {
const [authToken, setAuthToken] = useState<string | null>(null);
const [ authError, setAuthError ] = useState(null)
const [user, setUser] = useState<UserType | null>(null);
useEffect(() => {
const token = localStorage.getItem('access-token');
if (token) {
setAuthToken(token);
AuthService.getUserProfile(token).then(userData => {
setUser(userData);
}).catch(error => {
console.error('Error al obtener el perfil del usuario:', error);
});
} else {
setAuthToken(null);
setUser(null);
}
const handleStorageChange = () => {
const token = localStorage.getItem('access-token');
if (token) {
setAuthToken(token);
AuthService.getUserProfile(token).then(userData => {
setUser(userData);
}).catch(error => {
console.error('Error al obtener el perfil del usuario:', error);
});
} else {
setAuthToken(null);
setUser(null);
}
};
window.addEventListener('storage', handleStorageChange);
return () => {
window.removeEventListener('storage', handleStorageChange);
};
}, []);
const login = async (email: string, password: string) => {
try {
await AuthService.login(email, password, async (userData) => {
setUser(userData)
const token = await getAuthToken();
setAuthToken(token);
});
} catch (err) {
setAuthError(err.message)
}
};
const logout = () => {
setAuthToken(null);
setUser(null);
AuthService.logout()
};
return (
<AuthContext.Provider value={{ authToken, user, login, logout, authError }}>
{children}
</AuthContext.Provider>
);
}
const useAuthContext = ():AuthState => {
const context = useContext(AuthContext);
if (!context) {
throw new Error("useAuthContext must be used within an AuthProvider");
}
return context;
}
export default useAuthContext;
http.service.ts
export class HttpAPI {
public static async fetch(url: string, options: RequestInit): Promise<any> {
const response = await fetch(url, options);
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.errors ? errorData.errors[0].msg : 'Network response was not ok');
}
return response.json();
}
public static async get(url: string, options?: RequestInit): Promise<any> {
return this.fetch(url, { method: 'GET', ...options });
}
public static async post(url: string, body: object, accessToken?: string): Promise<any> {
return this.fetch(url, {
method: 'POST',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify(body),
});
}
}
So I am trying to catch the error message and set it into setAuthError for later rendering it from m authErrorCard.tsx
AuthErrorCard.tsx
"use client"
import Globe from "../svgs/Globe"
interface AuthErrorCardProps {
errorMessage: string;
}
export const AuthErrorCard = ({ errorMessage }: AuthErrorCardProps) => {
if(!errorMessage) return null;
return (
<div className="flex items-start w-[400px] p-4 bg-[#ff4c3f26] gap-3 mb-6 rounded-[5px]">
<Globe/>
<div className="flex flex-col w-full h-full">
<p className="text-white text-sm font-bold">Oops! There was and error when trying to login</p>
<span className="text-xs text-[#E79F9F]">{errorMessage}</span>
</div>
</div>
)
}
LoginContainer.tsx
"use client"
import useAuthContext from "@/contexts/authContext";
import { AuthErrorCard } from "./AuthErrorCard";
import LoginForm from "./LoginForm";
export const LoginContainer = () => {
const { authError } = useAuthContext();
console.log(authError)
return (
<>
{authError && <AuthErrorCard errorMessage={authError} />}
<LoginForm/>
</>
);
}
I am always getting either null
or err.response is undefined
, I had the idea that the issue was because in my api I was returning the error as a response and not as an error, but I´ve tried returning a new Error
, but instead I was not able to access the error message.