To implement a URL shortener service using Node.js, Express, and PostgreSQL, follow these steps:

1. Set up the project
2. Install required packages
3. Configure the database connection
4. Create the database schema
5. Implement the API endpoints
6. Test the application

### 1. Set up the project

Create a new directory for your project and navigate to it in your terminal.

```bash
mkdir url-shortener
cd url-shortener
```

Initialize a new Node.js project by running `npm init -y`.

### 2. Install required packages

Install the following packages: express, pg (PostgreSQL client for Node.js), dotenv (to manage environment variables), and nanoid (to generate unique short codes).

```bash
npm install express pg dotenv nanoid
```

### 3. Configure the database connection

Create a `.env` file in the root of your project and add the following content, replacing the placeholders with your actual PostgreSQL credentials:

```
DATABASE_URL=postgres://username:password@localhost/dbname
```

Create a `db.js` file in the root of your project and add the following code to configure the database connection:

```javascript
const { Pool } = require('pg');
require('dotenv').config();

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});

module.exports = {
  query: (text, params) => pool.query(text, params),
};
```

### 4. Create the database schema

Create a new file called `schema.sql` in the root of your project and add the following SQL code to create a table for storing URLs:

```sql
CREATE TABLE IF NOT EXISTS urls (
  id SERIAL PRIMARY KEY,
  original_url VARCHAR(2048) NOT NULL,
  short_code CHAR(7) UNIQUE NOT NULL
);
```

Now run this script to create the table in your PostgreSQL database:

```bash
psql -f schema.sql "postgres://username:password@localhost/dbname"
```

### 5. Implement the API endpoints

Create a new file called `app.js` in the root of your project and add the following code to set up the Express server and implement the required API endpoints:

```javascript
const express = require('express');
const db = require('./db');
const { nanoid } = require('nanoid');

const app = express();
app.use(express.json());

// Create a new short URL
app.post('/api/shorten', async (req, res) => {
  const originalUrl = req.body.url;
  if (!originalUrl) {
    return res.status(400).json({ error: 'URL is required' });
  }

  try {
    const shortCode = nanoid(7);
    await db.query(
      'INSERT INTO urls (original_url, short_code) VALUES ($1, $2)',
      [originalUrl, shortCode]
    );

    res.json({ shortCode });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Failed to shorten URL' });
  }
});

// Retrieve the original URL by its short code
app.get('/api/:shortCode', async (req, res) => {
  const shortCode = req.params.shortCode;

  try {
    const result = await db.query(
      'SELECT original_url FROM urls WHERE short_code = $1',
      [shortCode]
    );

    if (result.rows.length === 0) {
      return res.status(404).json({ error: 'Short code not found' });
    }

    res.json({ url: result.rows[0].original_url });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Failed to retrieve URL' });
  }
});

// Redirect users to the original URL when they visit the short link
app.get('/:shortCode', async (req, res) => {
  const shortCode = req.params.shortCode;

  try {
    const result = await db.query(
      'SELECT original_url FROM urls WHERE short_code = $1',
      [shortCode]
    );

    if (result.rows.length === 0) {
      return res.status(404).send('Short code not found');
    }

    res.redirect(result.rows[0].original_url);
  } catch (err) {
    console.error(err);
    res.status(500).send('Failed to redirect');
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});
```

### 6. Test the application

Start your server by running `node app.js`.

Now you can test your API endpoints using a tool like curl or Postman:

- Create a new short URL by sending a POST request to `/api/shorten` with a JSON body containing the `url` field.
- Retrieve the original URL by its short code by sending a GET request to `/api/:shortCode`.
- Visit the short link in your browser (e.g., `http://localhost:3000/abcdefg`) and make sure it redirects you to the original URL.

That's it! You've implemented a basic URL shortener service using Node.js, Express, and PostgreSQL.
Node.js, Express 및 PostgreSQL을 사용하여 URL 단축기 서비스를 구현하려면 다음 단계를 따르세요.

1. 프로젝트 설정
2. 필요한 패키지 설치
3. 데이터베이스 연결 구성
4. 데이터베이스 스키마 생성
5. API 엔드포인트 구현
6. 애플리케이션 테스트

### 1. 프로젝트 설정

프로젝트를 위한 새 디렉터리를 생성하고 터미널에서 해당 디렉토리로 이동합니다.

```bash
mkdir url-shortener
cd url-shortener
```

`npm init -y`.

### 2를 실행하여 새 Node.js 프로젝트를 초기화합니다. 필요한 패키지 설치

다음 패키지를 설치합니다: express, pg(Node.js용 PostgreSQL 클라이언트), dotenv(환경 변수 관리용), nanoid(고유한 단축 코드 생성용).

```bash
npm install express pg dotenv nanoid
```

### 3. 데이터베이스 연결 구성

프로젝트 루트에 `.env` 파일을 생성하고 다음 내용을 추가하여 자리 표시자를 실제 PostgreSQL 자격 증명으로 바꿉니다:

```
DATABASE_URL=postgres://username:password@localhost/dbname
```

프로젝트 루트에 `db.js` 파일을 생성하고 다음 코드를 추가하여 데이터베이스 연결을 구성합니다:

```javascript
const { Pool } = require('pg');
require('dotenv').config();

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});

module.exports = {
  query: (text, params) => pool.query(text, params),
};
```

### 4. 데이터베이스 스키마 생성

프로젝트 루트에 `schema.sql`이라는 새 파일을 생성하고 다음 SQL 코드를 추가하여 URL을 저장하는 테이블을 만듭니다:

```sql
CREATE TABLE IF NOT EXISTS urls (
  id SERIAL PRIMARY KEY,
  original_url VARCHAR(2048) NOT NULL,
  short_code CHAR(7) UNIQUE NOT NULL
);
```

이제 이 스크립트를 실행하여 PostgreSQL 데이터베이스에 테이블을 생성합니다:

```bash
psql -f schema.sql "postgres://username:password@localhost/dbname"
```

### 5. API 엔드포인트 구현

프로젝트 루트에 `app.js`라는 새 파일을 생성하고 다음 코드를 추가하여 Express 서버를 설정하고 필요한 API 엔드포인트를 구현하세요:

```javascript
const express = require('express');
const db = require('./db');
const { nanoid } = require('nanoid');

const app = express();
app.use(express.json());

// Create a new short URL
app.post('/api/shorten', async (req, res) => {
  const originalUrl = req.body.url;
  if (!originalUrl) {
    return res.status(400).json({ error: 'URL is required' });
  }

  try {
    const shortCode = nanoid(7);
    await db.query(
      'INSERT INTO urls (original_url, short_code) VALUES ($1, $2)',
      [originalUrl, shortCode]
    );

    res.json({ shortCode });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Failed to shorten URL' });
  }
});

// Retrieve the original URL by its short code
app.get('/api/:shortCode', async (req, res) => {
  const shortCode = req.params.shortCode;

  try {
    const result = await db.query(
      'SELECT original_url FROM urls WHERE short_code = $1',
      [shortCode]
    );

    if (result.rows.length === 0) {
      return res.status(404).json({ error: 'Short code not found' });
    }

    res.json({ url: result.rows[0].original_url });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Failed to retrieve URL' });
  }
});

// Redirect users to the original URL when they visit the short link
app.get('/:shortCode', async (req, res) => {
  const shortCode = req.params.shortCode;

  try {
    const result = await db.query(
      'SELECT original_url FROM urls WHERE short_code = $1',
      [shortCode]
    );

    if (result.rows.length === 0) {
      return res.status(404).send('Short code not found');
    }

    res.redirect(result.rows[0].original_url);
  } catch (err) {
    console.error(err);
    res.status(500).send('Failed to redirect');
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});
```

### 6. 애플리케이션 테스트하기

`node app.js`를 실행하여 서버를 시작합니다.

이제 curl 또는 Postman과 같은 도구를 사용하여 API 엔드포인트를 테스트할 수 있습니다.

- `url` 필드가 포함된 JSON 본문으로 `/api/shorten`에 POST 요청을 전송하여 새 짧은 URL을 생성합니다. 
- `/api/:shortCode`로 GET 요청을 전송하여 단축 코드로 원본 URL을 검색합니다.
- 브라우저에서 단축 링크를 방문합니다(예, http://localhost:3000/abcdefg`)를 방문하여 원래 URL로 리디렉션되는지 확인합니다.

이것으로 끝입니다! Node.js, Express, PostgreSQL을 사용하여 기본적인 URL 단축 서비스를 구현했습니다.