© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
1주차 Contents NodeJS 란 NodeJS API NodeJS Package Manager REST API ExpressJS 간단한 CRUD 만들기 (실습)
1. NodeJS 란? (1) Javascript 브라우저에서 사용할 수 있는 유일한(?) 언어 (2) ECMAScript ECMA-262 기술 규격에 따라 정의하고 있는 표준화된 스크립트 프로그래밍언어 즉, Javascript의 스펙 이면서 NodeJS의 스펙 이라고 할 수 있다. (3) V8 Engine Google에서 만든 오픈 소스이고 고성능 JavaScript 및 WebAssembly 엔진 2. NodeJS API NodeJS Optical Tutorial
(0) Global Module API Namespace 까지 입력 후 Tab 두 번
(1) FileSystem
(2) OS (3) Path
(4) HTTP
https.request | http.request (5) URL
(6) process
process.argv process.argv0process.cwd() process.env.PWD process.init.
(7) Timers
timers/promise promise 방식으로 setTimeout, setInterval, setImmediate, scheduler 를 사용할 수 있음 scheduler (8) Assert (9) command 3. NodeJS Package Manager (1) 소개 npm is the world's largest software registry. Open source developers from every continent use npm to share and borrow packages, and many organizations use npm to manage private development as well.
npm은 세계 최대의 소프트웨어 레지스트리입니다. 모든 대륙의 오픈 소스 개발자는 npm을 사용하여 패키지를 공유하고 차용하며 많은 조직에서 npm을 사용하여 비공개 개발도 관리합니다.
(2) commands (feat. package.json)
4. REST API REST RE presentational S tate T ransferHTTP를 제대로 사용하기 위해 설계된 아키텍쳐 (≠ protocal) 구성 행위(Verb) - HTTP METHOD자원(RESOURCE) - URI표현(Representations) 원칙 METHOD
역할
POST
POST를 통해 해당 URI를 요청하면 리소스를 생성합니다.
GET
GET를 통해 해당 리소스를 조회합니다.
리소스를 조회하고 해당 도큐먼트에 대한 자세한 정보를 가져온다.
PUT
PUT를 통해 해당 리소스를 수정합니다.
DELETE
DELETE를 통해 리소스를 삭제합니다.
URI ⇒ 정보의 자원 표현 자원에 대한 행위 ⇒ HTTP Method(GET, POST, PUT, DELETE)로 표현
GET POST PUT PATCH DELETE Status (상태코드) 1XX: 정보 제공 응답 상태코드
이 임시적인 응답은 지금까지의 상태가 괜찮으며 클라이언트가 계속해서 요청을 하거나 이미 요청을 완료한 경우에는 무시해도 되는 것을 알
이 코드는 서버가 요청을 수신하였으며 이를 처리하고 있지만, 아직 제대로 된 응답을 알려줄 수 없음을 알림
2XX: 성공적인 응답 상태코드
클라이언트의 요청을 정상적으로 수행
클라이언트가 어떠한 리소스 생성을 요청, 해당 리소스가 성공적으로 생성됨
요청에 대해서 보내줄 수 있는 콘텐츠가 없지만, 헤더는 의미있을 수 있습니다. 사용자-에이전트는 리소스가 캐시된 헤더를 새로운 것으로 업데이트 할 수 있습니다.
3XX: Redirect 응답 상태코드
301
이 응답 코드는 요청한 리소스의 URI가 변경되었음을 의미
(응답 시 Location header에 변경된 URI를 적어줌)
이것은 캐시를 목적으로 사용됩니다. 이것은 클라이언트에게 응답이 수정되지 않았음을 알려주며, 클라이언트는 계속해서 응답의 캐시된 버전을 사용
4XX: client 에러 상태코드
클라이언트의 요청이 부적절 할 경우 사용하는 응답 코드
클라이언트가 인증되지 않은 상태에서 보호된 리소스를 요청했을 때 사용하는 응답 코드
유저 인증상태와 관계 없이 응답하고 싶지 않은 리소스를 클라이언트가 요청했을 때 사용하는 응답 코드
- 서버: 요청받은 리소스를 찾을 수 없음
- 브라우저: 알려지지 않은 URL
- endpoint는 있으나 적절하지만 리소스 자체는 존재하지 않음
클라이언트가 요청한 리소스에서는 사용 불가능한 Method를 이용했을 경우 사용하는 응답 코드
401: 로그인 X 403: 로그인은 했으나 권한이 없음 (관리자 페이지에 일반 사용자가 접근) 5XX: server 에러 상태코드
서버에 문제가 있을 경우 사용하는 응답 코드
이 오류 응답은 서버가 요청을 처리하는 데 필요한 응답을 얻기 위해 게이트웨이로 작업하는 동안 잘못된 응답을 수신했음을 의미
- 서버가 요청을 처리할 준비가 되지 않았음
- 유지보수를 위해 작동이 중단되거나 과부하가 걸렸을 때
RESTful
REST API
REST API의 장점 독립성
REST API는 사용되는 기술과 독립적 Java Go Python NodeJS .NET etc API 설계에 영향을 주지 않고 다양한 프로그래밍 언어로 클라이언트 및 서버 애플리케이션을 모두 작성 통신에 영향을 주지 않고 양쪽의 기본 기술을 변경할 수 있습니다.
확장성
클라이언트-서버 상호 작용을 최적화 ⇒ 확장이 용이함 과거의 PHP, JSP로 만들던 사이트(MPA) ⇒ 현대의 사이트 (SPA + REST API) 잘 만들어진 REST API를 이용하여 서비스 확장 가능 오픈 API 처럼 사용 가능 ⇒ 확장성 Stateless한 특징으로 서버가 과거 클라이언트 요청 정보를 유지할 필요가 없기 때문에 서버 로드를 제거
유연성
각 부분이 독립적으로 발전할 수 있도록 다양한 서버 구성 요소를 단순화하고 분리 서버 애플리케이션의 플랫폼 또는 기술 변경은 클라이언트 애플리케이션에 영향을 주지 않도록 할 수 있음
!Stop!
확장 가능하다 = 인터페이스를 잘 정의한다 = 주입할 수 있다.
4. ExpressJS (1) 소개 웹 애플리케이션
웹 및 모바일 애플리케이션을 위한 일련의 강력한 기능을 제공하는 간결하고 유연한 Node.js 웹 애플리케이션 프레임워크입니다.API
자유롭게 활용할 수 있는 수많은 HTTP 유틸리티 메소드 및 미들웨어를 통해 쉽고 빠르게 강력한 API를 작성할 수 있습니다.성능
Express는 기본적인 웹 애플리케이션 기능으로 구성된 얇은 계층을 제공하여, 여러분이 알고 있고 선호하는 Node.js 기능을 모호하게 만들지 않습니다.Frameworks
많은 유명한 프레임워크들이 Express를 기반으로 하고 있습니다.
(2) 실행
5. (실습) 간단한 CRUD 만들기 부록. 고민해볼 것 express를 http, https 등으로 직접 구현해보기
fs.access(file, constants.F_OK, (err) => {
console.log(`${file} ${err ? 'does not exist' : 'exists'}`);
});fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => {
if (err) throw err;
});fs.readFile('/etc/passwd', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});const data = JSON.stringify({ id: 'junil', name: '황준일' })
fs.writeFile('data.json', data, 'utf8', (err) => {
if (err) throw err;
console.log('The file has been saved!');
});try {
fs.accessSync('etc/passwd', constants.R_OK | constants.W_OK);
console.log('can read/write');
} catch (err) {
console.error('no access!');
}if (existsSync('/etc/passwd'))
fs.console.log('The path exists.');
}fs.mkdirSync('/tmp/a/apple');const data = fs.readFileSync('./data.json', 'utf8');const data = JSON.stringify({ id: 'junil', name: '황준일' });
fs.writeFileSync('./data.json', data, 'utf8');const http = require('http')
const port = process.env.PORT || 3000
const server = http.createServer((req, res) => {
res.statusCode = 200
res.setHeader('Content-Type', 'text/html')
res.end('<h1>Hello, World!</h1>')
})
server.listen(port, () => {
console.log(`Server running at port ${port}`)
})const server = http2.createSecureServer({
key: fs.readFileSync('localhost-privkey.pem'),
cert: fs.readFileSync('localhost-cert.pem')
});
server.on('error', (err) => console.error(err));
server.on('stream', (stream, headers) => {
// stream is a Duplex
stream.respond({
'content-type': 'text/html; charset=utf-8',
':status': 200
});
stream.end('<h1>Hello World</h1>');
});
server.listen(8443);const options = {
key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);const https = require('https');
const options = {
hostname: 'github.com',
port: 443,
path: '/',
method: 'GET'
};
const req = https.request(options, (res) => {
res.on('data', (d) => {
console.log(d.toString())
});
});
req.on('error', (e) => {
console.error(e);
});
req.end();> new URL('https://user:pass@sub.example.com:8080/p/a/t/h?query=string#hash');const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('What do you think of Node.js? ', (answer) => {
// TODO: Log the answer in a database
console.log(`Thank you for your valuable feedback: ${answer}`);
rl.close();
});setImmediate(() => console.log('setImmediate')); // 즉시 실행 (task queue에 올림)
setTimeout(() => console.log('setTimeout'), 1000); // 1초 뒤 실행
setInterval(() => console.log('setInterval'), 1000); // 1초 마다 실행
console.log('console.log');
// 출력 순서
// console.log => setImmediate => setTimeout => setIntervalconst {
setTimeout,
setImmediate,
setInterval,
scheduler,
} = require('timers/promises');
setImmediate().then(() => console.log('setImmediate'));
setTimeout(1000).then(() => console.log('setTimeout'));
scheduler.wait(100).then(() => console.log('scheduler.wait'));
scheduler.yield().then(() => console.log('scheduler.yield'));
async function main() {
const interval = 100;
for await (const startTime of setInterval(interval, Date.now())) {
const now = Date.now();
console.log(now);
if ((now - startTime) > 1000)
break;
}
console.log(Date.now());
}
main();$ node -p "1 + 2"
3
$ COMPUTED = $(node -p "1 + 2")
$ echo $COMPUTED
3
$ echo "node -p process length: $(node -p "Object.keys(process).length")"
node -p process length: 74
$ echo "timestamp: $(node -p "Date.now()")"
$ echo "random: $(node -p "Math.round(Math.random() * 1000000000)")"{
"name": "desktop",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}$ echo "console.log(Math.max(...process.argv.slice(2).map(Number)))" > index.js{
"name": "desktop",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"max:1-2": "node index.js 1 2",
"max:10-20-30": "node index.js 10 20 30"
},
"keywords": [],
"author": "",
"license": "ISC"
}$ npm run max:1-2
2
$ npm run max:10-20-30
30> npm install express
> npm install axios
> npm install -D jest
> npm install -D typescript{
"name": "desktop",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"max:1-2": "node index.js 1 2",
"max:10-20-30": "node index.js 10 20 30"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^0.27.2",
"express": "^4.18.1"
},
"devDependencies": {
"jest": "^28.1.3",
"typescript": "^4.7.4"
}
}$ npm uninstall express axios jest typescriptGET /users
GET /users/1
GET /users/6cd9cf7c-fe62-409a-aa8e-30541a41b87f
GET /comments
GET /comments/1
GET /posts
GET /posts/1
GET /posts?page=5%size=100&limit=100&search=부스트캠프
GET /users/1/posts
GET /users/1/comments
GET /posts/2/commentsPOST /users
POST /comments
POST /posts/1/comments
POST /users/2/posts
POST /users/2/comments
POST /users/2/posts/1/commentsPUT /users/1
PUT /comments/2
PUT /posts/3PATCH /users/1
PATCH /comments/2
PATCH /posts/3DELETE /users/1
DELETE /comments/2
DELETE /posts/3const express = require('express')
const app = express()
const port = 3000
app.get('/', function (req, res) {
res.send('Hello World!');
});
app.post('/', function (req, res) {
res.send('Got a POST request');
});
app.put('/user', function (req, res) {
res.send('Got a PUT request at /user');
});
app.delete('/user', function (req, res) {
res.send('Got a DELETE request at /user');
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})