Telegram Mini App

이승훈·2026년 2월 19일

NodeJS

구조

├/node_modules
├/modules
│├bot.js
│└sessions.js
├/routes
│├index.js
│└home.js
├/views
│└home.ejs
├/public
│└scripts
│ ├index.js
│ └home.js
├.env
├index.js
├package-lock.json
└package.json

패키지

"dependencies": {
  "express": "latest",
  "ejs": "latest",
  "cookie-parser": "latest",
  "node-telegram-bot-api" : "latest"
}
npm install

/

index.js

import express from 'express';
import cookieParser from 'cookie-parser';
import routes from './routes/index.js';
import sessions from './modules/sessions.js';

const ENV = process.env;
const CWD = process.cwd();

const app = express();

app.set('view engine', 'ejs');
app.set('views', `${CWD}/views`);

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
app.use('/public', express.static(`${CWD}/public`));
app.use((req, res, next) => {
  const userId = req.cookies.userId;
  if (userId && sessions.has(userId)) {
    res.locals.userInfo = sessions.get(userId);
  }
  next();
});
app.use(routes);

app.listen(ENV.SERVER_PORT, () => {
  console.log('서버가 실행 중입니다.');
});

modules/

bot.js

import TelegramBot from 'node-telegram-bot-api';

const bot = new TelegramBot(process.env.TOKEN, {
  polling: true,
  request: {
    agentOptions: {
      family: 4,
      keepAlive: true
    }
  }
});

bot.on('polling_error', (error) => {
  console.error('Polling error:', error.message);
});

export default bot;

sessions.js

const sessions = new Map();
export default sessions;

routes/

index.js

import express from 'express';
const router = express.Router();

import home from './home.js';
router.use('/', home);

export default router;

home.js

import express from 'express';
import sessions from '../modules/sessions.js';
import db from '../modules/bot.js';

const router = express.Router();

router.get('/', (req, res) => {
  res.render('home');
});

router.post('/', (req, res) => {
  const user = req.body;
  if (user) {
    const userId = user.id;
    const name = [user.last_name, user.first_name].filter(Boolean).join('');
    res.cookie('userId', id, {
      httpOnly: true, secure: true, sameSite: 'none'
    });
    sessions.set(String(id), { id, name });
    bot.sendMessage(userId, '앱이 실행됐습니다.');
    res.status(204).end();
  } else {
    res.status(400).end();
  }
});

export default router;

views/

home.ejs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <script src="https://telegram.org/js/telegram-web-app.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/eruda"></script>
  </head>
  <body>
    <p>Hello, World!</p>
    <script>eruda.init();</script>
    <script src="/public/scripts/index.js"></script>
    <script src="/public/scripts/home.js"></script>
  </body>
</html>

public/scripts/

index.js

const tg = window.Telegram.WebApp;
tg.ready();

home.js

async function initializeUser() {
  if (tg.initDataUnsafe && tg.initDataUnsafe.user) {
    try {
      const response = await fetch('/', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
		},
        body: JSON.stringify(tg.initDataUnsafe.user)
      });
      if (response.status === 204) {
		console.log('쿠키, 세션 등록 성공');
      } else {
        console.error("서버 응답 에러");
      }
    } catch (err) {
      console.error("네트워크 에러", err);
    }
  }
}

initializeUser();
profile
안녕하세요!

0개의 댓글