반응형

DB와 연결하고 포스트맨으로 API 테스트를 하던 중, 회원 등록 요청에서 아래와 같은 오류가 오류가 발생했다.

ValidationError: User validation failed: password: Path `password` is required., email: Path `email` is required.

↑ 오류 메시지

같이 확인해볼 코드는 register API, userSchema 코드와 포스트맨에서 보낸 request body(req.body), response body 부분이다.

// 회원 등록
app.post('/api/user/register', (req, res) => {
    try {
        const user = new User(req.body);
        console.log(user);
        const userData = user.save();
        return res.status(200).json({ success: true, user:userData});
    } catch {
        return res.status(400).json({ success: false, err});
    }
})

↑ register API (오류 발생)

const userSchema = mongoose.Schema({ // schema 필드 정의
    name: {
        type: String,
        maxLength: 50
    },
    email: {
        type: String,
        required: true,
        unique: true,
        lowercase: true,
        trim: true // 앞뒤 공백 제거
    },
    password: {
        type: String,
        required: true,
        trim: true,
        minLength: 5
    },
    role: {
        type: Number,
        default: 0
    }
})

↑ userSchema

{
    "name": "amanda",
    "email": "amanda@gmail.com",
    "password": "1234567"
}

↑ Postman - request body(req.body)

{
    "success": true,
    "user": {}
}

↑ Postman - response body

🚧 원인 분석

userSchema에서 email, password를 required: true를 설정하고 Postman에서 email, password의 값을 포함해 요청을 보냈음에도, Mongoose는 이 필드가 없다고 판단하며 validation 오류를 발생시킨 것이다.

Express는 기본적으로 요청 본문을 자동으로 파싱하지 않기 때문에, JSON 형식의 요청을 받을 경우 body-parser과 같은 미들웨어를 추가해줘야 req.body가 제대로 채워진다. 그래서 내가 작성한 코드로는 req.body가 undefined 였고, new User(req.body)에 들어가는 값도 비어 있으며, email과 password가 누락된 채 validation에 걸리게 된 것이다.

🛠️ 해결 과정

1. body-parser 미들웨어 추가

body-parser 모듈을 설치한다.

npm install body-parser

이후 코드 상단에 아래와 같이 등록한다.

const bodyParser = require('body-parser'); // HTTP 요청 본문(body) 파싱하는 미들웨어 불러오기

app.use(bodyParser.urlencoded( { extended: true })); // application/x-www-form-urlencoded
app.use(bodyParser.json()); // application/json

↑ register API

여기서 사용한 extended 옵션은 false가 기본이고, false를 설정할 경우 Node.js 기본 모듈인 querystring을 사용해 단순 구조만 파싱한다. true로 설정하면 qs 라이브러리를 사용해서 중첩된 객체나 배열 등 복잡한 구조도 파싱할 수 있다.

여기까지 설정하면 JSON 데이터를 정상적으로 받을 수 있게 된다.

2. async/await 적용

body-parser를 추가해도 여전히 Postman 응답에서 "user": {}처럼 빈 객체가 보였다. Mongoose의 user.save()가 비동기 함수인데 await를 붙이지 않아 저장이 완료되기 전에 응답을 보냈기 때문이다.

// 회원 등록
const bodyParser = require('body-parser'); // HTTP 요청 본문(body) 파싱하는 미들웨어 불러오기

app.use(bodyParser.urlencoded( { extended: true })); // application/x-www-form-urlencoded
app.use(bodyParser.json()); // application/json

app.post('/api/user/register', async (req, res) => {
    try {
        const user = new User(req.body);
        console.log(user);
        const userData = await user.save();
        return res.status(200).json({ success: true, user:userData});
    } catch {
        return res.status(400).json({ success: false, err});
    }
})

↑ register API

Mongoose의 save()는 Promise를 반환하며, 내부적으로 저장 전에 validation을 자동으로 실행한다.

await을 사용하지 않으면 저장이 완료되기도 전에 응답을 보내는 문제가 생길 수 있다.
이 경우 user.save()는 아직 실행 중인 Promise이므로, 응답에서 user: {}처럼 보일 수 있다.
따라서 await을 사용해 저장이 완료된 후 응답을 보내야 한다.

🧠 What I Learned

Express는 요청 본문을 파싱해주는 미들웨어가 필요하다. body-parser.json()을 등록하지 않으면 JSON 형식으로 보낸 데이터도 undefined 처리되어 validation 오류가 발생할 수 있다. user.save()는 비동기 함수이므로, 저장 완료를 보장하려면 await를 사용한다.

반응형
반응형

개발을 하다 보면 이미 작성한 커밋 메시지를 바꿔야 할 때가 있다. 가장 최근 메시지를 수정할 것인지, 과거 여러 이력을 포함하여 복수 커밋을 수정, 삭제 등 수정할 것인지 경우에 따라 커밋 메시지를 수정하는 법에 대해 알아보자.

가장 최근 커밋 수정, 과거 커밋 수정 2가지 경우에 대해 알아보자.

 

🧩 가장 최근 커밋 메시지 수정하기 (amend)

# 최근 커밋 수정하기 (커밋 메시지, 내용 변경)
git commit --amend

# 이미 원격 저장소에 푸시한 커밋을 강제로 업데이트하기
git push --force

# 수정할 커밋을 삭제하고 이전 상태로 완전히 되돌아가기
git reset --hard HEAD~1

# 원격 저장소 최신 상태 가져오기 (리셋 후 동기화)
git pull

가장 최근(commit HEAD) 하나의 커밋만 수정할 때 사용한다. 메시지뿐만 아니라 스테이징 된 파일 추가/삭제 모두 가능하다.
보통 방금 커밋한 내용을 바로 수정하거나 보완할 때 쉽고 간단하게 메시지를 수정할 수 있다.

이미 원격 저장소에 푸시한 경우, 수정한 커밋 메시지를 원격 저장소에 반영하려면 강제로 푸시해야 한다.
⚠️ 강제 푸시는 공동 작업자와의 충돌 위험이 있어서 반드시 협의 후 진행해야 한다.

커밋 메시지 수정 후 되돌리고 싶다면,
가장 최근 커밋 메시지를 바꾼 후, 원래 상태로 돌아가고 싶을 때 git reset을 실행한 후 원격저장소의 최신 상태 동기화를 실행(pull)한다.

HEAD~1은 바로 이전 커밋을 가리키며, --hard 옵션은 커밋 + 스테이징 영역 + 작업 디렉토리까지 모든 변경사항을 제거한다. 즉, 파일의 변경사항이 함께 삭제되는 것이다.
--soft 옵션은 커밋만 되돌리는 것으로 스테이징 영역, 작업 디렉토리는 유지된다. 커밋 내역을 확실하게 제거해야 하는 경우가 아니라면 soft 옵션을 사용하는 것을 권장한다.

 

🧩 과거 여러 커밋 메시지 수정하기 (rebase)

# 최근 커밋 대상으로 리베이스 작업 시작 (수정하고자 하는 커밋 수에 맞게 숫자를 조절)
# HEAD(최신 커밋) 기준으로 이전 2개 커밋까지 포함하여 인터렉티브 리베이스 시작
git rebase -i HEAD~2

# 초기 커밋(최초로 작성)을 포함하여 리베이스 작업 시작
git rebase -i --root

# 리베이스 중단 (취소)
git rebase --abort

# 리베이스 계속하기 (충돌 해결 후)
git rebase --continue

# 리베이스 완료 후 원격 강제 푸시
git push --force

# 현재 브랜치의 총 커밋 개수 확인
git rev-list --count HEAD

# 커밋 로그 간략히 확인 (한 줄로 축약된 커밋 히스토리를 최신순으로 보여줌)
git log -oneline

가장 최신 커밋이 아닌 과거의 커밋 메시지를 수정하기 위해 최근 2개의 커밋을 대상으로 인터렉티브 리베이스를 시작한다. 숫자 2는 최근으로부터 몇 번째 커밋을 수정할 건지에 따라 숫자를 조절할 수 있다.

 

📝 커밋 메시지 수정 과정 (Vim 기준)

1. `git rebase -i HEAD~2`명령어를 실행하면 텍스트 편집기가 열리고 커밋 목록이 pick으로 표시된다.

2. 수정하고자 하는 커밋의 pick을 reword로 변경한다.

3. ESC → :wq → Enter 를 눌러 저장한다.

4. reword로 지정한 커밋 메시지 편집창이 열리면, 원하는 메시지로 수정한 후, 다시 ESC → :wq → Enter로 저장/편집기를 종료한다.

 

🛠️ pick 외에 사용할 수 있는 명령어

pick - 해당 커밋을 그대로 사용
reword - 커밋 내용은 유지하고 메시지만 수정
edit - 해당 커밋 시점에서 멈추고 내용까지 수정 가능
squash - 이전 커밋과 합쳐서 하나의 커밋으로 만듦(메시지 편집도 가능; 어떤 커밋 메시지를 최종적으로 남길지)
fixup - 이전 커밋과 자동으로 합치되, 메시지는 유지 X
drop - 해당 커밋을 삭제

 

🧠 What I Learned

몇 번째 커밋을 수정하느냐에 따라, amend, rebase 중 어떤 명령어를 사용할지 알게 되었다. 
메시지 편집창이 따로 열리는 건지 모르고 pick → reword 수정 후 바로 커밋 메시지 부분을 고쳐서 뒤로 넘기니 수정이 되지 않았다. 2번째로 열리는 곳에서 커밋 메시지를 수정해야 수정이 반영된다.

 

 

반응형
반응형

클론 코딩을 진행하던 중, GitHub에 (1) 알람이 떴다. 확인해보니 "Secret scanning (1)"이라는 보안 경고가 발생했다는 알람이었다. 이는 MongoDB Atlas의 Database URI가 코드에 노출되었음을 감지한 것으로, 민감 정보 유출 위험이 있다는 내용이었다.

MongoDB Atlas 데이터베이스 URI 노출 시 GitHub에서 제안하는 대응 절차를 따라가며 실제로 문제를 해결한 과정을 알아보자.

# Remediation steps

Follow the steps below before you close this alert.

1. Rotate the secret if it's in use to prevent breaking workflows.
2. Revoke this MongoDB Atlas Database URI with credentials through MongoDB to prevent unauthorized access. [Learn more about MongoDB tokens.](https://gh.io/mongodb_atlas_db_uri_with_credentials)
3. Check security logs for potential breaches.
4. Close the alert as revoked.


1. Rotate the secret if it's in use to prevent breaking workflows.
- 의미: 기존 URI가 코드나 배포 환경에 쓰이고 있다면, 단순히 삭제하지 말고 새로운 URI로 먼저 교체해야 한다.
- 조치 방법
  1) MongoDB Atlas에 로그인
  2) 새 사용자 생성 또는 기존 사용자 비밀번호 재설정 (비밀번호 기반 인증일 경우)
  3) 기존 프로젝트 또는 애플리케이션 설정에서 새 URI로 환경변수 혹은 시크릿 값 업데이트 (🧩 dotenv 적용)

2. Revoke this MongoDB Atlas Database URI with credentials through MongoDB to prevent unauthorized access.
- 의미: 외부에 노출된 기존 자격증명은 더 이상 유효하지 않도록 완전히 무력화해야 한다.
- 조치 방법
  1) MongoDB Atlas → Project → Database Access
  2) 노출된 URI에서 사용된 사용자 계정 확인
  3) 해당 사용자 계정 삭제 또는 비밀번호 변경
      - 완전히 사용하지 않을 거면 삭제
      - 다른 데서 여전히 사용중이라면 비밀번호만 재설정

3. Check security logs for potential breaches.
- 의미: 노출된 URI로 접속 시도나 이상한 동작이 있었는지 확인해야 한다.
- 조치 방법
  1) MongoDB Atlas → Project → Activity Feed 또는 Cluster → Metrics → Connection Logs
  2) 최근 IP 주소, 위치, 접속 시간 확인
  3) 의심스러운 접속(평소와 다른 국가, 갑작스러운 대량 쿼리 등) 식별
  4) 필요한 경우 침해 가능성에 따라 데이터 백업, 감사 진행

4. Close the alert as revoked.
- 의미: GitHub Security Alert이나 기타 시스템에서 이번 사고에 대한 대응이 완료되었음을 명시한다.
- 조치 방법
  1) GitHub Repository → Security → Secret scanning alerts
  2) 해당 MongoDB URI 경고 클릭
  3) "Mark as revoked" 또는 "Close as revoked" 선택

이후 index.js에서 URI를 .env 파일로 분리하여 환경변수로 관리하도록 수정하고, 노출된 값을 코드에서 제거한 후 커밋했다.

하지만 이미 이전 커밋에 포함되어 노출되었던 URI는 여전히 GitHub의 Secret scanning 페이지에 기록되어 있었다.  
Git의 히스토리 자체를 수정하지 않는 이상 이전 커밋의 흔적은 그대로 남기 때문에, 원격 저장소를 삭제하고 새로 생성한 후 클론하여 재설정했다.

이번에는 .env 파일을 만들어보자.

🧩 dotenv로 환경변수 관리하기

URI가 코드에 하드코딩되어 있으면 보안상 위험할 뿐만 아니라, 협업 중에도 민감 정보가 노출될 수 있다. 이를 해결하기 위해 Node.js에서는 보통 .env 파일에 환경변수를 정의하고 dotenv 패키지를 사용해 이를 불러온다.

npmjs.com 의 Install과 Usage를 적용하여 환경 변수 만드는 방법을 적용했다.

 

npm install 명령어로 dotenv를 설치했다.

# npm
npm install dotenv --save

# yarn
yarn add dotenv

 

프로젝트 루트 경로에 .env 파일을 생성한다.
(🛠️ 루트 경로가 아닌 곳에 .env 파일을 생성해서 DB 연결이 안 됐음)

.env 파일에서 환경변수를 정의하는 방법은 다음과 같다.

# .env
# 변수명=값

PORT=5000
MONGODB_URI=mongodb+srv://<id>:<password>@....

 

 

.env 파일을 GitHub에 올리는 실수를 하지 않도록, .gitignore 파일에 .env 을 추가해준다.

프로젝트 루트에 있는 index.js  첫 줄에 다음 코드를 입력해서 환경변수를 불러온다.

require('dotenv').config();

 

.env로부터 불러온 환경변수를 사용하기 위해서는 `process.env.변수명` 키워드를 사용한다.

process.env.PORT
process.env.MONGO_URI

 

🛠️ .env 파일에 정의한 변수명과 process.env에서 불러온 이름이 달라서 undefined 상태가 되었다. .env 파일의 MONGODB_URI를 MONGO_URI로 수정해서 해결했다.

# .env
MONGODB_URI=mongodb+srv://~

# index.js
const { PORT, MONGO_URI } = process.env;
mongoose.connect(process.env.MONGO_URI)
        .then(() => console.log('MongoDB Connected'))
        .catch(err => console.error(err));


🧠 What I Learned

민감 정보는 절대 코드에 노출하거나 하드코딩하지 않고, 환경 변수로 관리해야 한다. 이번에는 혼자하는 프로젝트라 큰 문제가 되지 않았지만, 여러명이 함께하거나 회사에서 이런 일이 생기기 않도록 주의 또 주의!!

반응형
반응형

옵시디언에 자료가 점점 많이 쌓여서 지난주 폴더 정리를 진행했다.

독서 목록을 추가하기 위해 Book Search 플러그인을 실행하여 도서 목록을 추가하는데 다음과 같은 에러 메세지가 떴다.

Error 내용은 다음과 같다.

Template Error:
Couldn't find user script folder "Scripts"
Check console for more information

폴더를 정리하면서 Scripts 폴더를 삭제했기 때문인가보다.

휴지통을 보니 Scripts 폴더가 있음을 확인해서 원래 있던 경로로 위치를 옮겼다. 옵시디언 문서 및 폴더를 삭제한 곳을 따로 .trash라는 폴더로 지정해두길 잘한듯. 👍

 

반응형
반응형

Iterate with Lighthouse via DevTools' Audits Panel

✅ 문제 요약

경고 Image elements do not have [alt] attributes
웹페이지의 <img> 태그에 alt 속성이 누락되거나 비어 있는 경우, 시각장애인용 보조기술(스크린 리더 등)은 이미지의 내용을 제대로 전달할 수 없다. SEO 측면에서도 이미지 내용을 효과적으로 인덱싱 하지 못한다.

경고가 발생하는 원인은 다음과 같다.

  • alt 속성이 아예 없는 경우
  • alt 속성이 비어 있는 경우 (alt="")
  • alt 속성의 내용이 부정확하거나 무의미한 경우

🔧 수정 방법

모든 <img> 태그에 alt 속성을 추가하거나 이미지가 정보 전달을 목적으로 하지 않는 경우 alt=""로 명시한다.

  1. HTML <img> 태그로 수동 전환하여 alt 속성 추가
  • 이미지가 정보를 전달하는 경우, 간결하고 정확한 텍스트를 alt 속성으로 추가한다.
  • ALT 텍스트 작성 팁
    • 이미지를 보지 못하는 사용자도 내용을 이해할 수 있도록 핵심 정보를 포함시킨다.
    • 불필요한 단어(이미지, 사진 등)은 사용하지 않는다.
    • 예: "제품 판매량 추이를 나타낸 바 차트" (O), "바 차트 이미지" (X)
  • widthheight는 원본 비율로 지정한다. (Lighthouse 점수 향상에 기여)
  1. ARIA 속성 사용하기
  • 이미지에 대한 대체 텍스트를 제공하는 방법은 alt 속성 외에도 aria-labelaria-labelledby를 사용할 수 있다.
    • aria-label : 이미지 내용을 간결하게 설명할 때 사용
    • aria-labelledby : 페이지 내 다른 요소와 연관시킬 때 사용
  1. 장식용 이미지 처리
  • 장식적인 이미지 또는 이미 페이지 내에서 설명된 경우, alt=""로 지정하거나 `role="presentation"을 사용한다. 이렇게 하면 스크린 리더가 해당 이미지를 무시하도록 설정할 수 있다.
/* 수정 전 */
/* 수정 후 */ <img src="https://blog.kakaocdn.net/dna/cheNgM/btsNfejzTDU/AAAAAAAAAAAAAAAAAAAAABQaxM77-NnP72KYPcdSwRPWfzgVYY98gW_dtp62lQl4/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&expires=1756652399&allow_ip=&allow_referer=&signature=O7Uw1UWNwHpWh0AdYBNsvkArMYw%3D" alt="SAP BP 마스터 데이터 구조를 나타낸 다이어그램" width="800" height="391">

🔖 참고 자료

https://dequeuniversity.com/rules/axe/4.10/image-alt

반응형
반응형
Git 오류 메시지
fatal: unable to read tree

fatal: unable to read tree 오류 메시지는 Git이 해당 커밋 또는 트리 객체를 읽을 수 없어서 저장소에 문제가 생겼다는 메시지이다.
OneDrive 동기화 폴더에 저장소가 있었는데 OneDrive 연결을 해제하고 Document 하위로 Vault를 이동하던 중에 문제가 생긴 것 같다.

🛠️ 원인

  1. 파일 시스템 문제 또는 Git 내부 오류
  • NFS, Dropbox, Google Drive, OneDrive 같은 동기화 폴더에 저장소가 있을 경우 문제 발생 가능
  1. 디스크 오류 / 네트워크 오류 (원격 저장소에서 clone한 경우)
  • git clone 도중 강제 종료되었거나 네트워크 연결이 끊겨 저장소 일부만 복사된 경우에도 발생 가능
  1. Git 저장소가 손상됨 (repository corruption)
  • .git/object/폴더 내의 데이터가 손상되었거나 일부가 삭제된 경우
  • 특히 Git이 특정 트리 객체를 찾을 수 없을 때 fatal: unable to read tree 오류 출력

🧪 해결 방법

Step 1. 기존 폴더 삭제하기

Windows CMD 기준

rmdir /s /q "C:\Users\USER\Documents\Obsidian\wononul"

Windows PowerShell 기준

Remove-Item -Recurse -Force "C:\Users\USER\Documents\Obsidian\wononul"

Caution 위 명령어는 폴더를 강제로 삭제하므로, 중요한 파일이 있는 경우 반드시 백업 후 진행

Step 2. 원격 저장소에서 다시 clone

git clone (원격저장소 주소)

Step 3. 정상 여부 확인

cd (vault가 존재하는 디렉토리)  
git status  

정상적으로 clone이 완료되었다면 git status 명령어에서 오류 없이 현재 브랜치 상태를 출력한다.

반응형

+ Recent posts