hy30nq's blog

섹션 19: 더 많은 익스프레스: 템플릿을 사용한 정적 & 동적 콘텐츠(EJS) [49일차] 본문

Web/100일 코딩 챌린지 - Web Development

섹션 19: 더 많은 익스프레스: 템플릿을 사용한 정적 & 동적 콘텐츠(EJS) [49일차]

hy30nq 2024. 2. 2. 10:45
728x90






JSON이란 무엇인가?

JSON(JavaScript Object Notation)은 경량의 데이터 교환 포맷입니다. 사람이 읽고 쓰기 쉽고, 기계가 파싱하고 생성하기에 용이합니다. JSON은 두 가지 구조를 기반으로 합니다: 이름/값 쌍의 집합인 객체({ })와 값의 순서화된 리스트인 배열([ ]). 이는 현대 프로그래밍 언어의 대부분에서 쉽게 식별할 수 있는 데이터 구조입니다.

JSON의 특징과 장점

  • 가독성: JSON은 텍스트 기반 포맷으로, 사람이 읽기 쉽습니다.
  • 경량성: 데이터를 교환할 때 사용하는 대역폭을 최소화합니다.
  • 언어 독립성: 다양한 프로그래밍 언어에서 쉽게 사용할 수 있습니다.
  • 데이터 교환의 효율성: 웹 애플리케이션과 서버 간 데이터 전송에 최적화되어 있습니다.

JSON 사용 사례

  1. 웹 개발: 웹 페이지와 서버 간 비동기 데이터 교환(AJAX)에 널리 사용됩니다.
  2. API와 웹 서비스: 다양한 시스템 간 통합에 JSON 형식을 이용한 RESTful API가 많이 사용됩니다.
  3. 데이터 저장과 구성: 설정 파일이나 간단한 데이터 저장에 JSON 형식이 이용됩니다.

JSON의 구조

JSON은 두 가지 주요 구조를 가집니다:

  • 객체: 중괄호({ })로 둘러싸인 키와 값의 쌍으로 구성됩니다. 각 키는 문자열이며, 값은 다양한 타입(문자열, 숫자, 배열, 또 다른 객체 등)이 될 수 있습니다.
  • 배열: 대괄호([ ])로 둘러싸인 값의 순서화된 리스트입니다. 배열 내의 값은 어떤 타입이든 될 수 있습니다.

JSON 활용 예제

JSON의 간결하고 이해하기 쉬운 구조는 다양한 데이터 교환 요구를 쉽게 충족시킵니다. 예를 들어, 웹 애플리케이션에서 사용자 정보를 서버로 전송할 때 JSON 객체를 사용할 수 있습니다.

{
  "이름": "홍길동",
  "나이": 25,
  "이메일": "hong@gildong.com",
  "취미": ["독서", "여행"]
}

이 예제는 사용자의 이름, 나이, 이메일 주소, 취미를 포함하는 JSON 객체를 보여줍니다. 이처럼 JSON은 데이터를 명확하고 구조화된 방식으로 표현할 수 있게 해줍니다, 이는 개발자가 데이터를 더 쉽게 처리하고 활용할 수 있게 만듭니다.

JSON은 그 유연성과 간편함 덕분에 현대 웹 개발에서 필수적인 기술로 자리 잡았습니다. 데이터를 쉽고 효율적으로 교환하고자 하는 모든 개발자와 프로젝트에 권장됩니다.






JavaScript에서의 Path, FS, Express

JavaScript는 웹 페이지 개발뿐만 아니라 서버 측 애플리케이션 개발에도 널리 사용됩니다. Node.js 환경에서 JavaScript는 파일 시스템을 다루고, 웹 서버를 구축하는 데 필수적인 여러 모듈을 제공합니다. 여기서는 Node.js의 핵심 모듈인 Path와 FS, 그리고 웹 애플리케이션 프레임워크인 Express에 대해 소개합니다.

1. Path 모듈

Path 모듈은 파일 시스템 경로를 다루는 데 사용됩니다. 이 모듈을 사용하여 경로 문자열을 쉽게 조작할 수 있으며, 운영 체제 간의 차이를 자동으로 처리합니다.

  • 기능: 파일 경로 생성, 경로 정보 분석, 경로 문자열 정규화, 파일 확장자 처리 등
  • 사용 예: path.join(), path.resolve(), path.basename(), path.extname()
const path = require('path');

const filePath = path.join('/users', 'john', 'docs', 'letter.txt');
console.log(filePath); // '/users/john/docs/letter.txt' on POSIX, '\users\john\docs\letter.txt' on Windows

2. FS 모듈

FS(File System) 모듈은 파일 시스템에 접근하여 파일을 읽고 쓰는 기능을 제공합니다. 이 모듈을 통해 파일 생성, 삭제, 읽기, 쓰기 등의 작업을 할 수 있습니다.

  • 기능: 파일 읽기/쓰기, 파일 상태 확인, 디렉토리 생성/삭제 등
  • 사용 예: fs.readFile(), fs.writeFile(), fs.stat(), fs.mkdir(), fs.unlink()
const fs = require('fs');

fs.readFile('example.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data);
});

3. Express

Express는 Node.js를 위한 가장 인기 있는 웹 프레임워크 중 하나입니다. 간단한 웹 애플리케이션부터 복잡한 RESTful API까지 다양한 웹 서비스를 쉽고 빠르게 구축할 수 있게 해줍니다.

  • 기능: 라우팅, 미들웨어 지원, 템플릿 엔진 통합, 요청 처리, 응답 관리 등
  • 사용 예: 서버 생성, 라우트 정의, 미들웨어 추가, 서버 리스닝
const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(3000, () => {
  console.log('Server is running on http://localhost:3000');
});

결론

Path, FS, Express 모듈은 Node.js 환경에서 JavaScript로 서버 사이드 애플리케이션을 개발할 때 필수적인 도구입니다. 이 모듈들은 파일 시스템 작업, 웹 서버 구축, API 개발 등 다양한 기능을 제공하여 JavaScript의 활용 범위를 웹 브라우저에서 서버 측 애플리케이션으로 확장시킵니다.






ExpressJS의 express.urlencoded({ extended: false }) 미들웨어

ExpressJS에서 express.urlencoded({ extended: false }) 미들웨어는 클라이언트로부터 오는 요청의 본문(body)을 파싱하는 데 사용됩니다. 이 미들웨어는 주로 <form> 태그에서 제출된 데이터를 처리하거나, POST 요청에서 Content-Type이 application/x-www-form-urlencoded인 요청 본문을 파싱할 때 사용됩니다. 여기서 extended: false 옵션은 본문 데이터가 "URL-encoded" 형식으로 파싱될 때 사용되는 라이브러리를 지정합니다.

URL-Encoded 데이터

URL-Encoded 형식은 웹 폼 데이터를 서버로 전송할 때 사용되는 인코딩 방식입니다. 이 형식은 키-값 쌍을 &로 연결하고, 공백은 + 또는 %20으로, 특수 문자는 %로 인코딩합니다. 예를 들어, 사용자 이름과 비밀번호를 전송할 때 다음과 같이 인코딩될 수 있습니다: username=JohnDoe&password=123456.

extended 옵션

express.urlencoded() 함수는 extended 옵션을 받습니다. 이 옵션은 본문을 파싱할 때 사용되는 라이브러리를 선택합니다.

  • extended: true일 경우, qs 라이브러리를 사용하여 복잡한 객체와 배열을 허용하는 본문 파싱을 합니다. 이는 중첩된 객체를 표현할 수 있게 해줍니다.
  • extended: false일 경우, querystring 라이브러리를 사용하여 문자열과 배열만을 허용하는 본문 파싱을 합니다. 이는 간단한 키-값 쌍만을 처리할 수 있습니다.

미들웨어 사용 예제

const express = require('express');
const app = express();

// URL-encoded 데이터 파싱 미들웨어 적용
app.use(express.urlencoded({ extended: false }));

app.post('/login', (req, res) => {
  // req.body를 통해 폼 데이터에 접근
  const { username, password } = req.body;
  res.send(`Username: ${username}, Password: ${password}`);
});

app.listen(3000, () => {
  console.log('Server is running on http://localhost:3000');
});

결론

express.urlencoded({ extended: false }) 미들웨어는 Express 애플리케이션에서 클라이언트가 제출한 폼 데이터를 쉽게 처리할 수 있게 해줍니다. extended: false 옵션을 사용함으로써, 단순한 키-값 쌍을 처리하는 경우에 적합한 설정을 제공합니다. 이는 웹 개발에서 폼 데이터를 다루는 기본적이면서도 중요한 부분을 간소화해줍니다.






JavaScript에서의 new 키워드 이해하기

JavaScript는 프로토타입 기반의 언어로, 객체 지향 프로그래밍 패턴을 지원합니다. 이러한 패턴의 핵심 요소 중 하나가 바로 new 키워드입니다. new 키워드를 사용하면 생성자 함수를 통해 새로운 객체를 생성할 수 있습니다. 이 블로그 글에서는 new 키워드의 작동 원리와 사용 방법에 대해 자세히 알아보겠습니다.

new 키워드란?

new 키워드는 JavaScript에서 생성자 함수를 호출할 때 사용되며, 새로운 객체를 만들고 그 객체를 초기화합니다. 생성자 함수는 보통 대문자로 시작하는 관례를 따르며, new를 사용하여 호출될 때 this 키워드는 새롭게 생성된 객체를 가리킵니다.

new 키워드의 작동 과정

  1. 새 객체 생성: new 키워드는 먼저 빈 객체를 생성합니다.
  2. 프로토타입 연결: 생성된 객체의 [[Prototype]] (또는 __proto__) 속성이 생성자 함수의 prototype 객체를 가리키도록 설정합니다.
  3. 생성자 함수 실행: 생성자 함수의 본문이 실행되며, this는 새로 생성된 객체에 바인딩됩니다.
  4. 객체 반환: 생성자 함수가 명시적으로 객체를 반환하지 않으면, new 표현식은 this에 의해 참조된 새 객체를 반환합니다.

new 사용 예제

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};

const john = new Person('John', 30);
john.greet(); // "Hello, my name is John and I am 30 years old."

이 예제에서 Person 함수는 생성자 함수로 사용되며, new Person('John', 30)Person의 인스턴스를 생성합니다. 생성된 객체 johnPerson.prototype에 정의된 greet 메소드에 접근할 수 있습니다.

new와 객체 리터럴의 차이

new 키워드를 사용하여 객체를 생성하는 방법과 객체 리터럴 {}을 사용하는 방법 사이에는 중요한 차이가 있습니다. 객체 리터럴은 단순히 새 객체를 생성하고 초기화하는 반면, new 키워드는 생성자 함수를 통해 객체를 생성하므로, 생성된 객체는 생성자 함수의 프로토타입 체인을 상속받습니다. 이는 객체가 공통의 메소드나 속성을 공유할 수 있게 하며, 메모리를 효율적으로 사용할 수 있게 합니다.

결론

new 키워드는 JavaScript에서 객체 지향 프로그래밍을 구현하는 데 중요한 도구입니다. 생성자 함수와 함께 사용되어, 코드의 재사용성을 높이고, 메모리 사용을 최적화하며, 객체 간의 상속 관계를 설정하는 데 도움을 줍니다. 이러한 이유로, new 키워드의 작동 원리를 이해하고 올바르게 사용하는 것은 JavaScript 개발자에게 필수적인 기술입니다.






__dirname 이해하기: Node.js에서의 디렉토리 경로

Node.js 개발 과정에서 __dirname은 현재 실행 중인 스크립트가 위치한 디렉토리의 절대 경로를 나타내는 중요한 전역 변수입니다. 이 변수는 파일 시스템 작업을 수행할 때 기준 경로로 사용되며, 모듈이 위치한 디렉토리의 정확한 경로를 얻는 데 유용합니다.

__dirname의 특징

  • 절대 경로 제공: __dirname은 현재 모듈의 절대 경로를 문자열로 반환합니다. 이는 파일 시스템 작업을 상대 경로가 아닌 절대 경로를 기준으로 수행하려 할 때 유용합니다.
  • 보안과 신뢰성: 코드가 다른 환경이나 다른 디렉토리 구조에서 실행될 때, __dirname을 사용하면 경로 관련 문제를 방지할 수 있습니다. 이는 코드의 이식성과 신뢰성을 높여줍니다.
  • Node.js의 내장 변수: 별도의 선언이나 초기화 없이 Node.js 환경에서 바로 사용할 수 있습니다.

__dirname 사용 예시

const path = require('path');

// 현재 디렉토리의 절대 경로와 'logs' 디렉토리를 조합하여 새 경로 생성
const logDirectory = path.join(__dirname, 'logs');

console.log(logDirectory);
// 출력 예: /Users/yourname/projects/yourproject/logs

이 예시에서 path.join() 메소드는 __dirname 변수를 사용하여 현재 스크립트가 있는 디렉토리의 절대 경로와 'logs'라는 하위 디렉토리 이름을 결합합니다. 결과적으로, 운영 체제의 파일 시스템 구조에 관계없이 올바른 경로를 얻을 수 있습니다.

__dirnameprocess.cwd()의 차이

__dirname과 비슷한 목적으로 사용될 수 있는 또 다른 Node.js의 기능은 process.cwd()입니다. 그러나 두 변수 사이에는 중요한 차이가 있습니다:

  • __dirname: 현재 실행 중인 파일이 위치한 디렉토리의 절대 경로를 반환합니다.
  • process.cwd(): Node.js 프로세스가 시작된 작업 디렉토리를 반환합니다. 즉, Node.js 명령을 실행한 쉘 또는 터미널의 현재 디렉토리입니다.

이 두 가지는 특히 Node.js 애플리케이션을 다양한 디렉토리에서 실행할 때 경로 처리 방식에 영향을 미칩니다.

결론

__dirname은 Node.js 개발에서 파일 시스템 경로를 안전하고 신뢰성 있게 다루기 위해 필수적인 전역 변수입니다. 코드의 이식성과 유지 보수성을 향상시키는 데 중요한 역할을 하며, 다양한 환경과 디렉토리 구조에서의 안정적인 파일 접근을 보장합니다.






Node.js의 readFileSync()writeFileSync()

Node.js에서 파일 시스템 작업은 매우 중요한 부분입니다. 이 중 readFileSync()writeFileSync() 함수는 파일을 동기적으로 읽고 쓰는 기본적인 방법을 제공합니다. 이들 함수는 fs 모듈의 일부이며, 파일 처리 작업을 간단하고 직관적으로 수행할 수 있게 해줍니다.

readFileSync() 함수

readFileSync() 함수는 지정된 경로의 파일 내용을 동기적으로 읽어서 반환합니다. 이 함수를 사용할 때 Node.js는 파일의 모든 내용을 읽은 후에야 다음 코드를 실행합니다. 이는 파일 크기가 크거나 디스크 속도가 느린 경우 프로그램의 성능에 영향을 줄 수 있습니다.

  • 구문: fs.readFileSync(path[, options])
  • 매개변수:
    • path: 읽을 파일의 경로입니다.
    • options: 인코딩이나 반환될 데이터의 형식을 지정하는 객체입니다. options가 문자열인 경우, 인코딩을 의미합니다.
  • 반환 값: 기본적으로 Buffer 객체를 반환하지만, options에 문자열 인코딩('utf8' 등)을 지정하면 문자열을 반환할 수 있습니다.

예제:

const fs = require('fs');

// 파일 동기적으로 읽기
const data = fs.readFileSync('example.txt', 'utf8');
console.log(data);

writeFileSync() 함수

writeFileSync() 함수는 지정된 데이터를 파일에 동기적으로 쓰는 작업을 수행합니다. 이 함수를 사용하면 데이터가 완전히 파일에 쓰여진 후에야 다음 코드가 실행됩니다. 파일 쓰기 작업 중에 오류가 발생하면 예외가 발생하므로, try-catch 블록으로 예외 처리를 해야 합니다.

  • 구문: fs.writeFileSync(file, data[, options])
  • 매개변수:
    • file: 쓰기 작업을 할 파일의 경로입니다.
    • data: 파일에 쓸 데이터입니다.
    • options: 파일 쓰기 옵션을 지정하는 객체입니다. 인코딩, 모드, 플래그 등을 설정할 수 있습니다.
  • 반환 값: 없음.

예제:

const fs = require('fs');

// 파일에 데이터 동기적으로 쓰기
try {
  fs.writeFileSync('output.txt', 'Hello, World!', 'utf8');
  console.log('File written successfully');
} catch (err) {
  console.error('Error writing file:', err);
}

주의 사항

readFileSync()writeFileSync()는 동기적인 함수이기 때문에, 이들을 사용하는 동안 Node.js 이벤트 루프가 차단됩니다. 따라서 이러한 함수는 주로 애플리케이션의 시작 단계나 작업량이 많지 않은 스크립트에서 사용하는 것이 좋습니다. 서버와 같이 높은 I/O 처리량이 요구되는 환경에서는 비동기적인 방식(fs.readFile(), fs.writeFile() 등)을 사용하는 것이 더 적합합니다.

728x90