node.js 다운로드 확인node -v
npm -v
Express 설치 → node.js 프로젝트 생성npm install express
nodemon 패키지 설치 nodemon : 코드를 수정했을 때 서버를 즉시 재시작해 주는 툴—-save-dev 옵션을 사용한 겁니다.npm install --save-dev nodemon
VSCode extention REST Client 설치
package.json 에 "type": "module" 추가
▷ type을 module로 설정해야 import, export 같은 ES 모듈 문법을 사용
{
"dependencies": {
...
},
"devDependencies": {
...
},
"type": "module" // 추가!
}
node app.js를 입력하고 로컬 웹브라우저의 주소창에 localhost:3000/hello 등으로 요청을 보내면 자동으로 GET request가 되어서 화면에 Hello Express!가 출력되고, VSCode의 콘솔창에는 Server Started 메시지가 출력됨// app.js
import express from 'express';
const app = express();
app.get('/hello', (req, res) => {
res.send('Hello Express!');
})
app.listen(3000, () => console.log('Server Started'));
res.send : js 객체를 받아서 json으로 변환해서 반환app.js 파일에서 import tasks from './data/mock.js 를 부르고, app.get('/tasks', 로 변경하고 send(tasks) 로 수정해서 테스트해볼 수 있음// data/mock.js
const data = [
{
id: 1,
title: "Learn JavaScript",
isComplete: false,
createdAt: "2024-09-29T10:00:00Z",
updatedAt: "2024-09-29T12:00:00Z"
},
{
id: 2,
title: "Write a blog post",
isComplete: true,
createdAt: "2024-09-28T09:30:00Z",
updatedAt: "2024-09-29T08:00:00Z"
},
{
id: 3,
title: "Go for a walk",
isComplete: false,
createdAt: "2024-09-27T07:15:00Z",
updatedAt: "2024-09-27T09:45:00Z"
}
];
export default data;
Rest Client 사용!requests.http 파일 생성GET localhost:3000/hello 라고 작성하면 됨###로 구분해야 함GET http://localhost:3000/hello
###
GET http://localhost:3000/tasks?sort=oldest&count=3
문제점
만약 우리가 위의 js 코드에서 res.send 부분을 res.send('Bye Express!'); 로 수정하고 다시 request를 보낸다고 해도 바로 반영되지 않고, Ctrl+C로 서버를 끈 후 다시 시작해야 변경사항을 반영한 request가 나타남
→ 개발 상황에서 번거로움 ..
해결
이를 해결하기 위해 nodemon으로 서버를 시작해주면 js 코드 수정 → 저장 → request 다시 보내기의 과정만 거치면 바로 수정된 버전으로 request가 전송됨
nodemon으로 서버를 시작하는 방법? nodemon app.js
"scripts" 필드 수정
시작하는 명령어가 여러개가 되었으므로 이를 간단하게 하기 위해서 package.json에 단축어("scripts" 필드) 추가
서버 시작
"scripts" 필드에 저장된 명령어를 실행하려면 npm run 명령어 를 입력해야 하므로,
▷ 개발 환경에서 서버시작(nodemon app.js): npm run dev
▷ 실제 환경에서 서버시작(node app.js): npm run start
{
"dependencies": {
"express": "^4.21.0"
},
"devDependencies": {
"nodemon": "^3.1.7"
},
"type": "module",
"scripts": {
"dev": "nodemon app.js",
"start": "node app.js"
}
}
정의: http에서 ? 뒤에 나오는 일종의 조건문
예: sort=oldest&count=3 에서는 오래된 순서대로 정렬하고, 3개만 출력하라는 조건을 걸어주는 쿼리스트링
쿼리스트링 처리를 위해서는 app.js에서 미리 처리를 해줘야 함
// app.js
import express from 'express';
const app = express();
app.get('/hello', (req, res) => {
// 쿼리 파라미터 설명:
// sort: 'oldest'인 경우 오래된 테스크 기준, 나머지 경우 새로운 테스크 기준!
// count: 테스크 개수
const sort = req.query.sort;
const count = Number(req.query.count);
const compareFn =
sort === 'oldest'
? (a, b) => a.createdAt - b.createdAt
: (a, b) => b.createdAt - a.createdAt;
// 여기까지 쿼리파라미터 처리를 위한 조건문
res.send(tasks);
})
app.listen(3000, () => console.log('Server Started'));
/tasks/1, /tasks/2, ... 등 task의 id별로 url 리퀘스트를 각각 생성할 수는 없으므로 /tasks:id 처럼 다이나믹하게 변할 수 있는 url을 생성해서 사용함:으로 연결하며 url parameter라고 부르며, 기본적으로 req.params.id 등으로 불러오며 문자열로 정의되므로 만약 숫자로 사용하고자 하면 Number()로 바꿔줘야 함// app.js
import express from 'express';
const app = express();
app.get('/tasks:id', (req, res) => {
// 다이나믹 URL
const id = Number(req.params.id);
const task = tasks.find((task) => task.id === id);
if (task) {
res.send(task);
} else {
res.status(404).send({ message: "Cannot find given id" });
}
})
app.listen(3000, () => console.log('Server Started'));
GET http://localhost:3000/tasks/1 등으로 작성할 수 있다. Content-Type를, 그리고 한 줄을 띄우고 json body 작성POST http://localhost:3000/tasks
Content-Type: application/json
{
"title": "산책",
"description": "아파트단지 걷기"
}
단, Express는 request body로 전달되는 json 객체를 js 객체로 자동으로 전환해주지 않음
parsing: json → js 객체로 변환하는 과정
parsing을 하려면 app.use(express.json()) 로 app 전체에서 express.json 객체를 사용하도록 설정해야 함
request의 content-type이 application json이면 body를 parsing해서 js 객체로 만들고, request의 body property에 담아줌
// app.js
import express from 'express';
const app = express();
app.use(express.json()) // parsing 설정
app.post('/tasks', (req, res) => {
// 추후 DB로 대체될 예정
const newTasks = req.body;
const ids = tasks.map((task) => task.id);
newTask.id = Math.max(...ids) + 1;
newTask.isComplete = false;
newTask.ereatedAt = new Date();
newTask.updatedAt = new Date();
// post하기
tasks.push(newTask);
res.status(201).send(newTask);
})
app.listen(3000, () => console.log('Server Started'));
POST http://localhost:3000/tasks를 실행하고 나서 GET으로 바꿔서 tasks를 다시 한번 받아오며 tasks가 추가되었는지를 확인PATCH http://localhost:3000/tasks/1 // 수정하고자 하는 task의 id(1)로 변경
Content-Type: application/json
{
"isComplete": true // 수정하고자 하는 필드들 + 수정값들 설정
}
// app.js
import express from 'express';
const app = express();
app.patch('/tasks:id', (req, res) => {
// id에 해당하는 코드 가져오기
const id = Number(req.params.id);
const task = tasks.find((task) => task.id === id);
if (task) { // 만약 task가 있다면,
// request body에 전송되는 내용을 task 객체에 덮어쓰기
Object.keys(req.body).forEach((key)=>{
task[key] = req.body[key];
});
// task의 updatedAt field를 최신 시간으로 설정
task.updatedAt = new Date();
res.send(task);
} else {
res.status(404).send({ message: "Cannot find given id" });
}
})
app.listen(3000, () => console.log('Server Started'));
DELETE http://localhost:3000/tasks/1 // 삭제하고자 하는 task의 id(1)로 변경
// app.js
import express from 'express';
const app = express();
app.delete('/tasks:id', (req, res) => {
// 다이나믹 URL
const id = Number(req.params.id);
const task = tasks.findIndex((task) => task.id === id);
if (idx >= 0) { // id를 가진 task가 없다면 idx === -1이 되므로,
tasks.splice(idx, 1); // 인덱스 idx에서 시작해서 요소 1개를 지워라
res.sendStatus(204)// sendStatus: body 없이 상태코드만 보내고자 할 때
} else {
res.status(404).send({ message: "Cannot find given id" });
}
})
app.listen(3000, () => console.log('Server Started'));
MongoDB Atlas 에서 DB 생성, 연결 URL 준비하기
프로젝트 최상위 디렉토리에 env.js 파일 생성 후 준비된 연결 URL 붙여넣기
export const DATABASE_URL =
'mongodb+srv://codeit:<password>@mongodb-cluster.t5eg2vz.mongodb.net/todo-api?retryWrites=true&w=majority';
npm i mongoose
// app.js (api 작성된 파일)에서 다음과 같이 작성
import mongoose from 'mongoose';
import { DATABASE_URL } from './env.js';
// ...
mongoose.connect(DATABASE_URL).then(() => console.log('Connected to DB'));
npm run dev 를 실행하면 이제는 Server Started와 Connected to DB가 함께 출력됨models 폴더 생성 → 폴더 안에 Task.js 파일 생성// 예제: Task.js
import mongoose from 'mongoose';
const TaskSchema = new mongoose.Schema(
{
// id는 항상 unique하게 자동으로 생성되므로 작성할 필요 없음
title: {
type: String,
},
description: {
type: String,
},
isComplete: {
type: Boolean,
default: false,
},
}
{
// schema에 대한 옵션은 두번째 파라미터로 전달
timestamps: true,
}
);
const Task = mongoose.model('Task', TaskSchema); // 'Task'는 mongoDB의 collection 이름
export default Task;
data 폴더 아래에 mock.js, seed.js 파일 생성mock.js 파일에는 데이터 객체를 담은 배열 형태로 데이터를 담아두고, seed.js에서 불러와서 사용// seed.js
import mongoose from 'mongoose';
import { Groupdata, Commentdata, Postdata } from './mock.js';
import Group from '../models/Group.js';
import Comment from '../models/Comment.js';
import Post from '../models/Post.js';
import { DATABASE_URL } from '../env.js';
mongoose.connect(DATABASE_URL);
// Group
await Group.deleteMany({});
await Group.insertMany(Groupdata);
// Comment
await Comment.deleteMany({});
await Comment.insertMany(Commentdata);
// Post
await Post.deleteMany({});
await Post.insertMany(Postdata);
mongoose.connection.close(); // DB 연결 종료
// mock.js
const Groupdata = [
{
// id 필드 필요없음
title: 'rweoicm',
},
];
const Commentdata = [
{
// id 필드 필요없음
title: 'rweoicm',
},
];
const Postdata = [
{
// id 필드 필요없음
title: 'rweoicm',
},
];
// export default data;
export { Groupdata, Commentdata, Postdata };
(2) 작성한 seed.js 파일을 실행하기 위해 package.json 의 scripts 에 아래와 같이 단축어 추가 후 npm run seed 로 실행해서 mongoDB에 데이터 추가
"scripts": {
"dev": "nodemon app.js",
"start": "node app.js",
"seed": "node data/seed.js",
}
✨ 초기에는 mock.js만 사용해서 mongoDB 연결 없이 app.js를 작성해야 rest client를 활용해서 로직이 잘 동작하는지 확인할 수 있음. 그 이후 데이터베이스를 연결한 후 조금의 코드만 수정해주면 됨.
(1) dotenv 라이브러리 설치
npm install dotenv
(2) .env 파일 생성 (여기에서는 큰따옴표를 사용해야 함)
DATABASE_URL="mongodb+srv://<username>:<password>@todo-api.l0aepsl.mongodb.net/todo-api?retryWrites=true&w=majority"
PORT=3000
(3) app.js, seed.js 의 DATABASE_URL 가져오는 부분을 변경사항에 맞춰 수정하기
// 수정 전
import { DATABASE_URL } from './env.js';
// ...
mongoose.connect(DATABASE_URL).then(() => console.log('Connected to DB'));
// ...
app.listen(3000, () => console.log('Server Started'));
// 수정 후
// ...
import * as dotenv from 'dotenv';
dotenv.config();
// ...
mongoose.connect(process.env.DATABASE_URL).then(() => console.log('Connected to DB'));
// ...
app.listen(process.env.PORT || 3000, () => console.log('Server Started'));
cors 패키지 설치 후 app.js 파일 업데이트npm install cors
// app.js
import cors from 'cors';
// ...
const app = express();
app.use(cors());
app.use(express.json());
const app = express();
const corsOptions = {
origin: ['http://127.0.0.1:5500', 'https://my-todo.com'],
};
app.use(cors(corsOptions));
app.use(express.json());
(1) VSCode 터미널에서 순서대로 아래 커맨드 실행
git init
echo 'node_modules/\n.env\n*.http\n*.log\n*.gz\n.DS_Store' > .gitignore
.gitignore 파일을 생성: node_modules 디렉토리, .env 파일, .http 파일, 그리고 다른 것들 몇 가지는 GitHub에 올릴 필요가 없기 때문에 제외
(2) 좌측 메뉴에서 아래의 사진과 같이 Source Control을 선택하고 Changes 옆의 + 버튼을 클릭한 후 밑줄 친 부분에서 commit message를 작성하고 commit 버튼을 누르기
(3) push하고자 하는 github repository로 들어가면 초기세팅 페이지가 나올 때, 아래에 붉은 색으로 표시된 코드를 복사해서 VSCode 터미널에 붙여넣고 실행하기
→ github에서 새로고침해서 commit이 반영되었는지 확인하기

(1) render 회원가입 후 아래의 사진과 같이 webservice 클릭

(2) github 선택

조각집이란? 기억 저장 및 공유 서비스입니다.
본 페이지에 기록한 코드를 제외한 예시 프로젝트의 아이디어, api 명세서, 기능 아이디어 등을 포함하는 토이프로젝트의 모든 자료는 저작권법에 의해 보호받는 ㈜코드잇의 자산을 학습 목적으로 제공받아 사용했으며 무단 사용 및 도용, 복제 및 배포를 금합니다.
Copyright 2024 코드잇 Inc. All rights reserved.
초기세팅 출처: https://www.codeit.kr/topics/intro-to-javascript-backend/lessons/6302
Express로 API 만들기 출처: https://www.codeit.kr/topics/intro-to-javascript-backend/lessons/6317