Express.js: создаем первый сервер на JavaScript для новичков

Пройдите тест, узнайте какой профессии подходите
Сколько вам лет
0%
До 18
От 18 до 24
От 25 до 34
От 35 до 44
От 45 до 49
От 50 до 54
Больше 55

Для кого эта статья:

  • Новички в веб-разработке, которые хотят изучить серверную часть.
  • Разработчики, желающие улучшить свои навыки работы с Node.js и Express.js.
  • Студенты и участники курсов по веб-разработке, ищущие практическое руководство.

    Первые шаги в мир серверной разработки часто вызывают трепет и неуверенность. Когда я впервые столкнулся с необходимостью создать бэкенд для своего JavaScript-приложения, мне казалось, что это требует какой-то особой магии. Express.js разрушил этот миф. Этот элегантный и минималистичный фреймворк превращает сложное в простое, позволяя даже новичкам быстро запускать полноценные серверные приложения. Готовы создать свой первый сервер на JavaScript за считанные минуты? Давайте разберемся, как Express.js делает серверную разработку доступной и увлекательной. 🚀

Освоение Express.js – важный шаг к становлению полноценным веб-разработчиком. Программа Обучение веб-разработке от Skypro включает полноценный модуль по серверной разработке на Node.js и Express.js с реальными проектами. Вы научитесь создавать API, работать с базами данных и развертывать приложения в продакшн под руководством практикующих разработчиков. От новичка до профессионала всего за 9 месяцев – инвестиция в навыки, которые останутся с вами навсегда.

Что такое Express.js и его преимущества для веб-разработчиков

Express.js — это минималистичный и гибкий фреймворк для создания веб-приложений на Node.js. Если Node.js — это мощный двигатель, позволяющий JavaScript работать на сервере, то Express можно сравнить с элегантным кузовом спортивного автомобиля, придающим этой силе форму и управляемость. 🏎️

Созданный в 2010 году, Express стал стандартом де-факто для разработки серверных приложений в экосистеме Node.js. Он решает фундаментальную проблему: базовый Node.js требует написания большого количества шаблонного кода для обработки даже простых HTTP-запросов.

Александр Петров, Senior Backend Developer Помню свой первый коммерческий проект на Node.js без фреймворков. Клиенту нужно было простое API для мобильного приложения, и я решил, что справлюсь с чистым Node.js. Уже через неделю код превратился в спагетти из обработчиков запросов, проверок параметров и маршрутизации. Когда я переписал проект на Express, размер кодовой базы уменьшился вдвое, а читаемость выросла в разы. Клиент получил продукт раньше срока, а я навсегда влюбился в Express за его элегантность. С тех пор для меня стало правилом: не изобретай велосипед, если есть Express.

Ключевые преимущества Express.js:

  • Минимализм и гибкость — Express не навязывает жестких структур или шаблонов, давая разработчику свободу в организации кода
  • Высокая производительность — благодаря асинхронной природе Node.js, Express обрабатывает запросы быстро и эффективно
  • Богатая экосистема промежуточного ПО (middleware) — расширяйте функциональность приложения через простые подключаемые компоненты
  • Встроенная маршрутизация — интуитивно понятная система для обработки различных HTTP-методов и URL-путей
  • Поддержка шаблонизаторов — легкая интеграция с различными движками представлений (Pug, EJS, Handlebars)
Параметр Чистый Node.js Express.js
Размер кода для REST API ~300 строк ~100 строк
Обработка маршрутов Ручная через switch/case Встроенная система маршрутизации
Парсинг данных запроса Ручная реализация Простые middleware
Работа со статическими файлами Реализация вручную Одна строка кода
Кривая обучения Крутая Пологая

Express.js создан с учетом потребностей разработчиков, желающих быстро создавать надежные веб-приложения. Он прекрасно вписывается в современную архитектуру веб-приложений, будь то монолитный сайт или микросервисное API.

Пошаговый план для смены профессии

Установка и настройка Express.js: первые шаги

Начать работу с Express.js проще, чем может показаться на первый взгляд. Давайте разберем процесс установки и настройки шаг за шагом. Убедитесь, что у вас уже установлен Node.js — он является фундаментом для работы с Express. 📦

Создание проекта начинается с инициализации npm (Node Package Manager):

mkdir my-express-app
cd my-express-app
npm init -y

Команда npm init -y создаст файл package.json с настройками по умолчанию. Теперь установим сам Express:

npm install express

После установки создадим базовое приложение. Создайте файл app.js и добавьте следующий код:

JS
Скопировать код
const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
res.send('Привет, Express!');
});

app.listen(port, () => {
console.log(`Сервер запущен на http://localhost:${port}`);
});

Запустите сервер командой:

node app.js

Откройте браузер и перейдите по адресу http://localhost:3000. Вы увидите сообщение "Привет, Express!". Поздравляю, ваш первый сервер на Express.js запущен! 🎉

Для более удобной разработки рекомендую установить nodemon, который будет автоматически перезапускать сервер при изменении файлов:

npm install nodemon --save-dev

Добавьте скрипт в package.json:

json
Скопировать код
"scripts": {
"dev": "nodemon app.js",
"start": "node app.js"
}

Теперь можно запускать сервер в режиме разработки командой npm run dev.

Основные компоненты для настройки Express-приложения:

  • Middleware — промежуточное ПО для обработки запросов
  • Роутеры — для организации маршрутов
  • Обработчики ошибок — для корректной обработки исключений
  • Конфигурация окружения — настройка различных сред (разработка, тестирование, продакшн)

Пример более продвинутой настройки приложения:

JS
Скопировать код
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;

// Middleware для парсинга JSON
app.use(express.json());
// Middleware для парсинга данных форм
app.use(express.urlencoded({ extended: false }));
// Middleware для статических файлов
app.use(express.static('public'));

// Собственное middleware
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});

// Маршруты
app.get('/', (req, res) => {
res.send('Главная страница');
});

// Обработка ошибок
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Что-то пошло не так!');
});

app.listen(port, () => {
console.log(`Сервер запущен на http://localhost:${port}`);
});

Маршрутизация и обработка HTTP-запросов в Express.js

Маршрутизация — это сердце любого Express-приложения. Она определяет, как приложение отвечает на клиентские запросы к определенным конечным точкам (URL) и методам HTTP. 🛣️

Базовая структура маршрута в Express:

JS
Скопировать код
app.МЕТОД(ПУТЬ, ОБРАБОТЧИК)

Где:

  • МЕТОД — HTTP-метод (get, post, put, delete и т.д.)
  • ПУТЬ — путь на сервере (например, '/' или '/users')
  • ОБРАБОТЧИК — функция, которая выполняется при совпадении маршрута

Рассмотрим примеры различных маршрутов:

JS
Скопировать код
// Обработка GET запроса к корневому URL
app.get('/', (req, res) => {
res.send('Главная страница');
});

// Обработка POST запроса к /users
app.post('/users', (req, res) => {
// Здесь может быть код для создания пользователя
res.send('Пользователь создан');
});

// Обработка PUT запроса к /users/:id
app.put('/users/:id', (req, res) => {
const userId = req.params.id;
// Обновление пользователя
res.send(`Пользователь ${userId} обновлен`);
});

// Обработка DELETE запроса к /users/:id
app.delete('/users/:id', (req, res) => {
const userId = req.params.id;
// Удаление пользователя
res.send(`Пользователь ${userId} удален`);
});

Динамические сегменты URL обозначаются с помощью двоеточия (:) и доступны через объект req.params. Это позволяет создавать гибкие маршруты, которые могут обрабатывать различные значения:

JS
Скопировать код
app.get('/products/:category/:id', (req, res) => {
const category = req.params.category;
const productId = req.params.id;
res.send(`Товар ${productId} из категории ${category}`);
});

Express позволяет группировать маршруты с помощью Router — это особенно полезно для структурирования кода в крупных приложениях:

JS
Скопировать код
// userRoutes.js
const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
res.send('Список всех пользователей');
});

router.get('/:id', (req, res) => {
res.send(`Информация о пользователе ${req.params.id}`);
});

module.exports = router;

// app.js
const userRoutes = require('./userRoutes');
app.use('/users', userRoutes);

Теперь все маршруты в userRoutes.js будут доступны с префиксом '/users'.

Мария Соколова, Frontend Team Lead В 2021 году мы с командой работали над проектом, где фронтенд на React взаимодействовал с бэкендом на Express. Структура API быстро разрасталась и становилась запутанной. Точка перелома наступила, когда мы начали терять время на поиск нужных эндпоинтов в коде. Решением стала группировка маршрутов по функциональности с помощью Router. Мы создали отдельные файлы для маршрутов аутентификации, пользователей, продуктов и т.д. В итоге структура стала настолько интуитивно понятной, что даже новички в команде быстро ориентировались в API. А среднее время добавления новой функциональности сократилось с 3 дней до 1. Этот опыт научил меня, что правильная организация маршрутов — ключ к масштабируемому Express-приложению.

При обработке запросов в Express важно понимать, как получать и обрабатывать данные из различных источников:

Источник данных Способ доступа Требуемый middleware
URL-параметры req.params Не требуется
Query-параметры req.query Не требуется
Данные формы req.body express.urlencoded()
JSON-данные req.body express.json()
Заголовки запроса req.headers Не требуется
Cookies req.cookies cookie-parser

Работа с шаблонизаторами и статическими файлами

Express.js предоставляет удобные механизмы для работы как с динамическим контентом через шаблонизаторы, так и со статическими файлами. Это позволяет создавать полноценные веб-сайты с серверным рендерингом HTML или гибридные приложения. 🎨

Начнем с настройки статических файлов — это CSS, JavaScript, изображения и другие ресурсы, которые сервер отдает клиенту без изменений:

JS
Скопировать код
// Все файлы из директории 'public' будут доступны как статические
app.use(express.static('public'));

// Можно задать виртуальный префикс для статических файлов
app.use('/static', express.static('public'));

Если у вас в директории public есть файл style.css, он будет доступен по URL /style.css или /static/style.css соответственно.

Для динамического генерирования HTML Express предлагает множество шаблонизаторов. Наиболее популярные:

  • EJS — простой синтаксис, похожий на HTML с включениями JavaScript
  • Pug (ранее Jade) — минималистичный синтаксис с отступами вместо тегов
  • Handlebars — логически простые шаблоны с минимальной логикой
  • Nunjucks — мощный шаблонизатор с наследованием макетов

Настройка шаблонизатора на примере EJS:

sh
Скопировать код
// Установка EJS
npm install ejs

// Настройка в app.js
app.set('view engine', 'ejs');
app.set('views', './views'); // Директория с шаблонами

Теперь создадим простой шаблон. В директории views создайте файл index.ejs:

HTML
Скопировать код
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1><%= heading %></h1>

<ul>
<% users.forEach(function(user) { %>
<li><%= user.name %> – <%= user.email %></li>
<% }); %>
</ul>
</body>
</html>

Теперь можно отрендерить этот шаблон с данными:

JS
Скопировать код
app.get('/', (req, res) => {
res.render('index', {
title: 'Моё Express приложение',
heading: 'Список пользователей',
users: [
{ name: 'Алексей', email: 'alex@example.com' },
{ name: 'Мария', email: 'maria@example.com' },
{ name: 'Иван', email: 'ivan@example.com' }
]
});
});

Для организации более сложных шаблонов удобно использовать частичные представления (partials) и макеты (layouts). Например, в EJS можно включать один шаблон в другой:

HTML
Скопировать код
<!-- views/partials/header.ejs -->
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<header>
<nav>
<a href="/">Главная</a>
<a href="/about">О нас</a>
<a href="/contact">Контакты</a>
</nav>
</header>

<!-- views/partials/footer.ejs -->
<footer>
<p>&copy; 2023 Мой сайт на Express.js</p>
</footer>
</body>
</html>

<!-- views/home.ejs -->
<%- include('partials/header') %>

<main>
<h1><%= heading %></h1>
<p>Добро пожаловать на мой сайт!</p>
</main>

<%- include('partials/footer') %>

При работе с шаблонизаторами и статическими файлами важно помнить о безопасности:

  • Не передавайте напрямую пользовательский ввод в шаблоны без экранирования
  • Используйте Content-Security-Policy для защиты от XSS-атак
  • Настройте правильные заголовки кэширования для статических файлов
  • Рассмотрите использование CDN для раздачи статического контента в продакшне

Создание REST API и подключение к базам данных

Express.js идеально подходит для создания RESTful API и интеграции с различными базами данных. Это важнейший навык для современного веб-разработчика, позволяющий создавать полноценные серверные приложения. 🔌

Начнем с создания простого REST API для управления задачами (todo list):

JS
Скопировать код
const express = require('express');
const app = express();
const port = 3000;

app.use(express.json());

// Временное хранилище задач
let tasks = [
{ id: 1, text: 'Изучить Express.js', completed: false },
{ id: 2, text: 'Создать REST API', completed: false }
];

// Получить все задачи
app.get('/api/tasks', (req, res) => {
res.json(tasks);
});

// Получить задачу по ID
app.get('/api/tasks/:id', (req, res) => {
const task = tasks.find(task => task.id === parseInt(req.params.id));
if (!task) return res.status(404).json({ error: 'Задача не найдена' });
res.json(task);
});

// Создать новую задачу
app.post('/api/tasks', (req, res) => {
if (!req.body.text) return res.status(400).json({ error: 'Текст задачи обязателен' });

const newTask = {
id: tasks.length + 1,
text: req.body.text,
completed: false
};

tasks.push(newTask);
res.status(201).json(newTask);
});

// Обновить задачу
app.put('/api/tasks/:id', (req, res) => {
const task = tasks.find(task => task.id === parseInt(req.params.id));
if (!task) return res.status(404).json({ error: 'Задача не найдена' });

task.text = req.body.text || task.text;
task.completed = req.body.completed !== undefined ? req.body.completed : task.completed;

res.json(task);
});

// Удалить задачу
app.delete('/api/tasks/:id', (req, res) => {
const taskIndex = tasks.findIndex(task => task.id === parseInt(req.params.id));
if (taskIndex === -1) return res.status(404).json({ error: 'Задача не найдена' });

tasks.splice(taskIndex, 1);
res.status(204).send();
});

app.listen(port, () => {
console.log(`Сервер запущен на http://localhost:${port}`);
});

Это базовая реализация CRUD-операций (Create, Read, Update, Delete) для API задач. В реальных проектах данные хранятся в базе данных, а не в памяти.

Подключение к базе данных MongoDB с использованием Mongoose (популярная ODM-библиотека):

sh
Скопировать код
npm install mongoose

// db.js
const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/taskdb', {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log('Подключено к MongoDB'))
.catch(err => console.error('Ошибка подключения к MongoDB:', err));

// Определение схемы и модели
const taskSchema = new mongoose.Schema({
text: { type: String, required: true },
completed: { type: Boolean, default: false },
createdAt: { type: Date, default: Date.now }
});

module.exports = mongoose.model('Task', taskSchema);

// app.js – интеграция с API
const Task = require('./db');

// Получить все задачи
app.get('/api/tasks', async (req, res) => {
try {
const tasks = await Task.find();
res.json(tasks);
} catch (err) {
res.status(500).json({ error: 'Ошибка сервера' });
}
});

// Создать задачу
app.post('/api/tasks', async (req, res) => {
try {
const task = new Task({
text: req.body.text
});
const savedTask = await task.save();
res.status(201).json(savedTask);
} catch (err) {
res.status(400).json({ error: err.message });
}
});

Для работы с SQL базами данных можно использовать ORM Sequelize:

sh
Скопировать код
npm install sequelize pg pg-hstore

// db.js
const { Sequelize, DataTypes } = require('sequelize');

const sequelize = new Sequelize('postgres://user:password@localhost:5432/taskdb');

// Определение модели
const Task = sequelize.define('Task', {
text: {
type: DataTypes.STRING,
allowNull: false
},
completed: {
type: DataTypes.BOOLEAN,
defaultValue: false
}
});

// Синхронизация модели с базой данных
sequelize.sync();

module.exports = Task;

Для обеспечения безопасности API важно добавить валидацию, аутентификацию и авторизацию:

  • Валидация данных — проверка входных данных (можно использовать библиотеку Joi или express-validator)
  • Аутентификация — проверка личности пользователя (JWT, сессии, OAuth)
  • Авторизация — проверка прав доступа к ресурсам
  • Обработка ошибок — централизованная обработка и форматирование ошибок API

Пример промежуточного ПО (middleware) для защиты маршрутов с JWT:

JS
Скопировать код
// authMiddleware.js
const jwt = require('jsonwebtoken');

function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];

if (!token) return res.status(401).json({ error: 'Требуется аутентификация' });

jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) return res.status(403).json({ error: 'Недействительный токен' });
req.user = user;
next();
});
}

// Использование в маршрутах
app.get('/api/protected', authenticateToken, (req, res) => {
res.json({ message: 'Это защищенный ресурс', user: req.user });
});

Работа с Express.js — захватывающее путешествие от простого к сложному. Вы начинаете с создания базового сервера, затем добавляете маршруты, подключаете шаблонизаторы, интегрируетесь с базами данных и, наконец, создаете полнофункциональные API с поддержкой аутентификации и авторизации. Каждый шаг открывает новые возможности и технические решения, позволяя вам вырасти от новичка до уверенного бэкенд-разработчика. Express.js — это не просто фреймворк, это инструмент, который растет вместе с вами и вашими проектами.

Загрузка...