자바스크립트 기본이 왜 중요한지 현업을 하다가 뼈저리게 느꼈던 적이 있었다.그 때를 회상하고 같은 일이 발생한다면 더 빠르게 해결하기 위해 이 글을 작성해본다.
TLDR;
throw..catch문으로 에러객체 잡아 처리해준 썰
회사에서 진행하던 프로젝트는 맨처음에 CRA로 만들어졌으나 개발 초반에 대시보드 제작과 정렬, 그리고 학습의 이유로 Next.js를 이용한 플젝으로 이관되었다. 이 과정에서 NextAuth를 새로 사용하게 되었는데, 한창 잘 사용하다가 요구사항이 생겼다.
"🙏 민주님, 로그인시 서버에서 돌려주는 메세지를 받아서 보여주세요"
일반적으로 로그인하듯이 그냥 에러처리 해주면 되는 거 아닌가?라고 생각했으나, 쓱 살펴보니 NextAuth provider에서 에러 발생시 에러 객체를 잡을 수 없는 상황이 왔고, 해결책을 찾아 NextAuth 코드를 까보기 시작했다.
확인해보니 에러메세지 분기처리를 NextAuth에서 제공하고 있는 signIn함수가 돌려주는 status code로 처리하려 발생하는 이슈로, next-auth가 서버에서 돌려주는 메세지와 상관없이 status code를 401로 리턴해주고 있기 때문에 메세지 분기 처리가 제대로 안되었었다. 같은 401 에러더라도 사용자에게 추가로 정확한 안내를 위해 서버에서 리턴해주는 메세지를 보여줘야 했다.
해결 방법을 찾아 NextAuth 공식문서를 뒤지고, 내부 코드를 까보기 시작했다. 분명, 아래 부분에서 에러 발생하는 에러를 잡아서 처리해주면 되는 것인데, 죽어도 에러 객체가 잡히지 않는 것이었다.
// [...nextauth].ts
async authorize(credentials, req) {
try {
const res = await axios.post(process.env.NEXTAUTH_URL || '', credentials);
if (res.data) {
return res.data;
}
} catch (e) {
// 여기서 error를 잡아보니 원치 않는 값이 나온다.
}
return null;
},
...중략
공식문서를 참고하며 코드를 까고 까고 또 까고 들어가다 보니 위 authorize함수에서 하는 post요청이 callback.ts
를 돌아 signIn 함수의 처리결과로 Promise로 리턴되어 처리된다는 것을 알아낼 수 있었다. 그리고는 코드를 하나하나 확인하기 시작했다.
//callbacks.ts
// ...중략
else if (provider.type === "credentials" && method === "POST") {
const credentials = body
let user: User
try {
user = (await provider.authorize(credentials, {
query,
body,
headers,
method,
})) as User
if (!user) {
return {
status: 401,
redirect: `${url}/error?${new URLSearchParams({
error: "CredentialsSignin",
provider: provider.id,
})}`,
cookies,
}
}
} catch (error) {
return {
status: 401,
redirect: `${url}/error?error=${encodeURIComponent(
(error as Error).message
)}`,
cookies,
}
}
// ... 중략 엄청 길었다..
스택오버플로우글처럼 signIn함수의 예외처리로 해주려는데 아예 메세지가 보이지 않는 상황이었다. 😂
결론적으로 돌고돌아 찾아낸 방법은 throw문으로 에러객체를 던져 받는 것이었다. throw 문에 대한 공식문서를 보면 다음과 같이 설명되어 있다.
throw문은 사용자 정의 예외를 발생(throw)할 수 있습니다. 예외가 발생하면 현재 함수의 실행이 중지되고 (throw 이후의 명령문은 실행되지 않습니다.), 제어 흐름은 콜스택의 첫 번째 catch 블록으로 전달됩니다. 호출자 함수 사이에 catch 블록이 없으면 프로그램이 종료됩니다.
그리고 예제는 다음과 같았는데, 원래는 getRectArea
에서 예외가 발생할 경우 그냥 if 문을 빠져나갔겠지만, throw를 통해 발생시킨 예외가 catch블록으로 전달되어 추가로 처리가 가능하단 것을 알 수 있었다.
function getRectArea(width, height) {
if (isNaN(width) || isNaN(height)) {
throw new Error('Parameter is not a number!');
}
}
try {
getRectArea(3, 'A');
} catch (e) {
console.error(e);
// Expected output: Error: Parameter is not a number!
}
따라서 callback.ts
안의 catch문안에서 에러객체를 잡아 return해주기 위해 결론적으로는 authorize함수에서 예외발생시에 throw문을 통해 예외를 발생시켜주었다.
async authorize(credentials, req) {
try {
const res = await axios.post(process.env.NEXTAUTH_URL || '', credentials);
if (res.data) {
return res.data;
}
} catch (e) {
// 여기에서 에러 잡아서 메세지만 받아 돌려주도록 함
throw new Error(e.response.data.msg);
}
return null;
},
이렇게 하고 보니 에러 발생시에 던져준 메세지를 callback함수를 통해 signIn함수로 잘 던져주어 나는 최종적으로 돌려받는 객체에 들어있는 메세지를 사용자에게 보여줄 수 있었다. 내가 필요했던건 throw new Error
이 문장 한 줄이었는데, 여기까지 오며 Nextauth 공식문서를 엄청 뒤져야했다. 역시 자바스크립트를 더 깊게 공부해야 한다는 것을 몸소 느낀 지점이었다.
나중에 저도 같은 상황이 올 수도 있을거 같을때 너무나 도움되는 글이에요!