Day to_day

[하루한끼_백엔드] Express Request 확장하기 본문

Project

[하루한끼_백엔드] Express Request 확장하기

m_inglet 2022. 11. 1. 23:35
728x90
반응형

1차 프로젝트에서는 자바스크립트로 서버를 구현했었지만 이번 2차 프로젝트에선 타입스크립트를 사용하기로 했다. 

전에 사용했던 유저 MVP만 코드 재활용하여 사용하였고, 타입스크립트 문법에 맞춰 타입들을 지정해주니 대부분의 오류는 해결되었다.

 

하지만 그 중 몇 시간을 잡아먹으며 해결이 어려웠던 오류가 있었는데...

 

그것은 바로 Express Request 확장하는 부분이다.

 

 

아래의 코드는 로그인 인증 방식을 작성한 코드이다.

import { Response, Request, NextFunction } from "express";
import jwt from "jsonwebtoken";

function login_required(req: Request, res: Response, next: NextFunction) {
  // request 헤더로부터 authorization bearer 토큰을 받음.
  const userToken = req.headers["authorization"]?.split(" ")[1] ?? "null";

  // 이 토큰은 jwt 토큰 문자열이거나, 혹은 "null" 문자열임.
  // 토큰이 "null" 일 경우, login_required 가 필요한 서비스 사용을 제한함.
  if (userToken === "null") {
    console.log("서비스 사용 요청이 있습니다.하지만, Authorization 토큰: 없음");
    res.status(400).send("로그인한 유저만 사용할 수 있는 서비스입니다.");
    return;
  }

  // 해당 token 이 정상적인 token인지 확인 -> 토큰에 담긴 user_id 정보 추출
  try {
    const secretKey = process.env.JWT_SECRET_KEY || "secret-key";
    const jwtDecoded: any = jwt.verify(userToken, secretKey);
    const user_id = jwtDecoded.user_id;
    req.currentUserId = user_id;
    next();
  } catch (error) {
    res.status(400).send("정상적인 토큰이 아닙니다. 다시 한 번 확인해 주세요.");
    return;
  }
}

export { login_required };

이때 'req.currentUserId' 이 부분에서 다음과 같은 오류가 났다.

Property 'currentUserId' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.

한마디로 Request에 정의되어있지 않은 currentUserId라는 property를 임의로 추가했기 때문에 발생한 에러이고, type을 커스텀해줘야 한다는 사실을 알게 되었다.

 

 

 

 

 

 

해결 방법


우선 타입 지정해주는 부분을 따로 파일로 빼서 코드를 작성해줘야 한다.

  •  'index.d.ts' 파일
import express from "express";

declare global{
	namespace Express {
		export interface Request {
		  currentUserId?: string;
		}
	}
}

나는 위와 같이 currentUserId를 string으로 지정해주었다. 유저의 토큰 값을 보고 그 유저의 id를 주는 request였기 때문에 string 타입이다.

 

여기서 중요한 것은 이렇게 코드 작성을 해둔 것을 어디에 넣어두냐!

 

처음엔 'src/types/index.d.ts' 경로로 넣어줬는데 원래 내가 참고한 사이트에서는 'src/types/express/index.d.ts'였는데 사이에 있는 express 경로가 의미가 없다고 생각해서 빼줬는데 뭔가 계속 다른 오류가 나서 하나하나 바꿔서 넣다 보니 express를 빼고 진행했었다. 

 

하지만 결과적으로 express 경로를 추가해줘야 한다는 것!

결국 경로는 back/src/types/express/index.d.ts에 파일을 위치시켰다.

 

 

그리고 그 경로를 tsconfig.json 파일에 넣어줘야 한다.

  • tsconfig.json 파일
{
  "compilerOptions": {
    "module": "commonjs",
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "target": "es2017",
    "sourceMap": true,
    "outDir": "./bin",
    "baseUrl": "./",
    "typeRoots": ["./src/types","./node_modules/@types"],
    "incremental": true,
    "skipLibCheck": true,
    "strictNullChecks": false,
    "noImplicitAny": false,
    "strictBindCallApply": false,
    "forceConsistentCasingInFileNames": false,
    "noFallthroughCasesInSwitch": false,
    "esModuleInterop": true
  }
}

중요하게 바꿀 부분은 "typeRoots"이다. 

위와 같이 넣어주고, "./src/types"가 앞쪽에 "./node_modules/@types"가 뒤쪽에 배치되어야 한다.

 

 

 

해결 단계

1. index.d.ts 파일 생성 및 코드 삽입

2. type/express/index.d.ts 경로 확인

3. tsconfig.json 파일 typeRoots 수정

 

 


Ref

Express Request 확장하기

https://blog.doitreviews.com/development/2020-03-26-extend-express-request-type-in-typescript/

 

How to extend the Express Request object in Typescript

https://blog.logrocket.com/extend-express-request-object-typescript/

 

728x90
반응형