Разработка веб-приложения для хранения заметок с использованием Express.js.
Современные веб-приложения играют важную роль в организации и управлении личной информацией. Одной из популярных категорий таких приложений являются нотатники — сервисы для создания, хранения и редактирования заметок. С помощью заметок пользователи могут быстро фиксировать идеи, списки задач, важные мысли или любые другие данные, нуждающиеся в сохранении и быстром доступе. В этой статье мы подробно рассмотрим процесс разработки простого, но функционального веб-приложения для хранения заметок, используя популярный веб-фреймворк Express.js.
Express.js — это минималистичный и гибкий веб-фреймворк для Node.js, который позволяет быстро разрабатывать серверные приложения и RESTful API. Благодаря простоте настройки и большому сообществу, Express.js становится отличным выбором для реализации как небольших проектов, так и масштабируемых решений. Мы рассмотрим архитектуру приложения, работу с данными, маршрутизацию, обработку запросов и ответы, а также основные аспекты безопасности и организацию пользовательского интерфейса.
Основные требования и архитектура приложения
Перед началом программирования важно определить ключевые функциональные требования к нашему приложению для заметок. Такой подход позволяет структурировать весь процесс разработки и избежать лишних сложностей на ранних этапах.
Наше приложение должно обеспечить следующие возможности:
- Создание новых заметок с заголовком и текстом;
- Просмотр списка всех заметок с возможностью выбора конкретной;
- Редактирование и удаление уже существующих заметок;
- Простая и интуитивно понятная навигация;
- Обработка ошибок и валидация данных.
Архитектурно приложение будет представлять собой классический клиент-сервер: сервер на Express.js будет обрабатывать HTTP-запросы, взаимодействовать с базой данных или файловой системой для хранения заметок, а клиентский интерфейс будет отправлять запросы и отображать полученную информацию.
Выбор способа хранения данных
Существует несколько вариантов хранения заметок: использование реляционных или NoSQL баз данных, файловая система либо в некоторых случаях — хранение только на клиенте. Для простоты и быстрого старта мы рассмотрим два возможных варианта:
- JSON-файл — удобен для небольших приложений и демонстрационных проектов. Все заметки хранятся в одном или нескольких файлах на сервере;
- MongoDB — более масштабируемый и привычный вариант, основанный на NoSQL базе данных, хорошо интегрирующийся с Node.js.
В рамках этой статьи мы остановимся на хранении заметок в JSON-файле, что позволит сосредоточиться на изучении работы Express.js без необходимости настройки БД. При этом методы взаимодействия с данными и маршрутизация будут универсальными и легко адаптируемыми под полноценную базу в будущем.
Настройка проекта и установка зависимостей
Перед началом разработки создадим новую папку для проекта и инициализируем в ней Node.js проект. Для этого используется команда, которая создаст файл конфигурации package.json с основными метаданными.
Далее установим необходимые пакеты. Основным является Express.js, который будет отвечать за обработку HTTP-запросов и маршрутизацию. Для удобства работы с формами и JSON запросами понадобится middleware для разбора тела запросов.
Шаги настройки проекта
- Создайте каталог проекта:
mkdir notes-app
и перейдите в него. - Инициализируйте проект командой:
npm init -y
. - Установите Express.js:
npm install express
. - Установите дополнительный пакет для автоматической перезагрузки сервера во время разработки —
nodemon
(опционально):npm install -D nodemon
. - Создайте файл
index.js
, который станет точкой входа для сервера.
Ваш package.json файл после установки должен содержать примерно такую структуру с зависимостями:
Поле | Значение |
---|---|
name | notes-app |
version | 1.0.0 |
dependencies |
|
devDependencies |
|
Создание базового сервера на Express.js
После установки всех необходимых модулей приступим к реализации базового сервера на Express.js. Он будет слушать запросы по определенному порту и обрабатывать маршруты.
Для начала опишем в файле index.js
минимальный серверный код:
const express = require('express');
const app = express();
const PORT = 3000;
// Middleware для парсинга JSON тела запросов
app.use(express.json());
// Пример простого маршрута
app.get('/', (req, res) => {
res.send('Добро пожаловать в приложение для хранения заметок!');
});
app.listen(PORT, () => {
console.log(`Сервер запущен на порту ${PORT}`);
});
Запустите сервер командой node index.js
или npx nodemon index.js
для автоматической перезагрузки при сохранении изменений. Откройте в браузере http://localhost:3000
и убедитесь, что выводится приветственное сообщение.
Обработка статических файлов
Для отображения клиентского интерфейса (HTML, CSS, JavaScript) необходимо подключить статические файлы. Express.js упрощает эту задачу с помощью встроенного middleware express.static
.
Создайте папку public
, куда будут помещены файлы интерфейса. Подключите ее к серверу следующим образом:
app.use(express.static('public'));
Теперь при запросах к серверу будет доступен весь фронтенд-контент. Это позволит сосредоточиться на разработке API и клиентских страниц отдельно.
Реализация CRUD операций для заметок
Ключевой функционал приложения — создание (Create), чтение (Read), обновление (Update) и удаление (Delete) заметок. Для этого настроим соответствующие маршруты с методами HTTP.
Перед реализацией маршрутов организуем работу с данными и определим модуль для чтения и записи заметок в JSON-файл.
Организация хранения заметок
Создадим в корне проекта файл notes.json
, который будет содержать массив заметок в формате JSON. Каждая заметка представляет собой объект с полями id
, title
, content
, а также отметкой времени.
Пример содержимого файла:
[
{
"id": 1,
"title": "Первая заметка",
"content": "Это тестовая заметка.",
"createdAt": "2025-05-16T07:00:00.000Z"
}
]
Для удобства создадим отдельный модуль notesStore.js
, который инкапсулирует операции чтения и записи заметок.
const fs = require('fs');
const path = require('path');
const NOTES_FILE = path.join(__dirname, 'notes.json');
function getAllNotes() {
if (!fs.existsSync(NOTES_FILE)) {
fs.writeFileSync(NOTES_FILE, JSON.stringify([]));
}
const data = fs.readFileSync(NOTES_FILE);
return JSON.parse(data);
}
function saveNotes(notes) {
fs.writeFileSync(NOTES_FILE, JSON.stringify(notes, null, 2));
}
function addNote(note) {
const notes = getAllNotes();
notes.push(note);
saveNotes(notes);
}
function updateNote(updatedNote) {
const notes = getAllNotes();
const index = notes.findIndex(n => n.id === updatedNote.id);
if (index !== -1) {
notes[index] = updatedNote;
saveNotes(notes);
return true;
}
return false;
}
function deleteNote(id) {
let notes = getAllNotes();
const lengthBefore = notes.length;
notes = notes.filter(n => n.id !== id);
if (notes.length < lengthBefore) {
saveNotes(notes);
return true;
}
return false;
}
module.exports = {
getAllNotes,
addNote,
updateNote,
deleteNote
};
Настройка маршрутов API
Подключите модуль хранения заметок в index.js
и создайте маршруты по REST-стандартам:
GET /api/notes
— получить все заметки;GET /api/notes/:id
— получить заметку по id;POST /api/notes
— создать новую заметку;PUT /api/notes/:id
— обновить существующую заметку;DELETE /api/notes/:id
— удалить заметку.
const express = require('express');
const app = express();
const { getAllNotes, addNote, updateNote, deleteNote } = require('./notesStore');
const PORT = 3000;
app.use(express.json());
// Получить все заметки
app.get('/api/notes', (req, res) => {
const notes = getAllNotes();
res.json(notes);
});
// Получить заметку по id
app.get('/api/notes/:id', (req, res) => {
const id = parseInt(req.params.id);
const notes = getAllNotes();
const note = notes.find(n => n.id === id);
if (note) {
res.json(note);
} else {
res.status(404).json({ error: "Заметка не найдена" });
}
});
// Создать новую заметку
app.post('/api/notes', (req, res) => {
const { title, content } = req.body;
if (!title || !content) {
return res.status(400).json({ error: "Необходимо указать заголовок и содержимое" });
}
const notes = getAllNotes();
const newId = notes.length ? notes[notes.length - 1].id + 1 : 1;
const newNote = {
id: newId,
title,
content,
createdAt: new Date().toISOString()
};
addNote(newNote);
res.status(201).json(newNote);
});
// Обновить заметку
app.put('/api/notes/:id', (req, res) => {
const id = parseInt(req.params.id);
const { title, content } = req.body;
if (!title || !content) {
return res.status(400).json({ error: "Необходимо указать заголовок и содержимое" });
}
const updatedNote = {
id,
title,
content,
createdAt: new Date().toISOString()
};
const success = updateNote(updatedNote);
if (success) {
res.json(updatedNote);
} else {
res.status(404).json({ error: "Заметка не найдена" });
}
});
// Удалить заметку
app.delete('/api/notes/:id', (req, res) => {
const id = parseInt(req.params.id);
const success = deleteNote(id);
if (success) {
res.json({ message: "Заметка удалена" });
} else {
res.status(404).json({ error: "Заметка не найдена" });
}
});
app.listen(PORT, () => {
console.log(`Сервер запущен на порту ${PORT}`);
});
Данные маршруты обеспечат работу основного API и позволят интегрировать клиентскую часть с сервером.
Создание клиентского интерфейса
Для взаимодействия пользователя с приложением разработаем простой фронтенд на HTML, CSS и JavaScript. Интерфейс должен позволять просматривать список заметок, создавать новые, редактировать и удалять существующие.
Файлы клиентской части разместим в папке public
. Опишем базовую структуру HTML и добавим стили и скрипт для управления логикой.
Структура HTML и стилизация
Пример файла public/index.html
с базовой разметкой и подключением внешнего CSS и JS:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Приложение для заметок</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
max-width: 800px;
}
h1 {
text-align: center;
color: #333;
}
#notesList {
list-style-type: none;
padding: 0;
}
#notesList li {
background: #f9f9f9;
border: 1px solid #ddd;
margin-bottom: 5px;
padding: 10px;
cursor: pointer;
}
#notesList li:hover {
background: #e9e9e9;
}
form {
margin-top: 20px;
display: flex;
flex-direction: column;
}
input[type="text"], textarea {
margin-bottom: 10px;
padding: 8px;
font-size: 16px;
}
button {
width: 100px;
padding: 8px;
font-size: 16px;
cursor: pointer;
}
.buttons {
display: flex;
gap: 10px;
}
</style>
</head>
<body>
<h1>Заметки</h1>
<ul id="notesList"></ul>
<form id="noteForm">
<input type="text" id="noteTitle" placeholder="Заголовок" required />
<textarea id="noteContent" placeholder="Содержание" rows="5" required></textarea>
<div class="buttons">
<button type="submit">Сохранить</button>
<button type="button" id="deleteBtn" style="display:none">Удалить</button>
<button type="button" id="cancelBtn" style="display:none">Отмена</button>
</div>
</form>
<script src="app.js"></script>
</body>
</html>
Логика работы на JavaScript
Создайте файл public/app.js
, в котором реализуйте работу с API и управление формой и списком заметок:
document.addEventListener('DOMContentLoaded', () => {
const notesList = document.getElementById('notesList');
const noteForm = document.getElementById('noteForm');
const titleInput = document.getElementById('noteTitle');
const contentInput = document.getElementById('noteContent');
const deleteBtn = document.getElementById('deleteBtn');
const cancelBtn = document.getElementById('cancelBtn');
let selectedNoteId = null;
// Загрузка заметок с сервера
async function loadNotes() {
const res = await fetch('/api/notes');
const notes = await res.json();
notesList.innerHTML = '';
notes.forEach(note => {
const li = document.createElement('li');
li.textContent = note.title;
li.dataset.id = note.id;
notesList.appendChild(li);
});
}
// Очистка формы
function clearForm() {
titleInput.value = '';
contentInput.value = '';
deleteBtn.style.display = 'none';
cancelBtn.style.display = 'none';
selectedNoteId = null;
}
// Отображение заметки в форме
async function showNote(id) {
const res = await fetch(`/api/notes/${id}`);
if (res.ok) {
const note = await res.json();
titleInput.value = note.title;
contentInput.value = note.content;
selectedNoteId = note.id;
deleteBtn.style.display = 'inline-block';
cancelBtn.style.display = 'inline-block';
}
}
// Обработка клика на заметку
notesList.addEventListener('click', e => {
if (e.target.tagName === 'LI') {
showNote(e.target.dataset.id);
}
});
// Обработка отправки формы
noteForm.addEventListener('submit', async e => {
e.preventDefault();
const title = titleInput.value.trim();
const content = contentInput.value.trim();
if (!title || !content) {
alert('Заполните заголовок и содержание');
return;
}
if (selectedNoteId) {
// Обновление заметки
const res = await fetch(`/api/notes/${selectedNoteId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title, content })
});
if (res.ok) {
await loadNotes();
clearForm();
} else {
alert('Ошибка при обновлении заметки');
}
} else {
// Создание новой заметки
const res = await fetch('/api/notes', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title, content })
});
if (res.ok) {
await loadNotes();
clearForm();
} else {
alert('Ошибка при создании заметки');
}
}
});
// Обработка удаления заметки
deleteBtn.addEventListener('click', async () => {
if (selectedNoteId && confirm('Удалить заметку?')) {
const res = await fetch(`/api/notes/${selectedNoteId}`, { method: 'DELETE' });
if (res.ok) {
await loadNotes();
clearForm();
} else {
alert('Ошибка при удалении заметки');
}
}
});
// Отмена редактирования
cancelBtn.addEventListener('click', () => {
clearForm();
});
// Первичная загрузка заметок
loadNotes();
});
Этот скрипт обеспечивает динамическое взаимодействие с серверным API: загрузка заметок, отображение данных, создание, обновление и удаление. Пользовательский опыт упрощён за счёт мгновенного обновления списка без перезагрузки страницы.
Особенности и улучшения
Рассмотренное приложение — базовый пример, демонстрирующий программирование REST API на Express.js и взаимодействие с клиентской частью через Fetch API. В реальной практике проект можно расширять и улучшать различными способами.
К основным направлениям развития относятся:
- Автентификация и авторизация пользователей. Добавление регистрации и входа, чтобы каждый пользователь имел свои заметки;
- Хранение данных в базе данных, например MongoDB или PostgreSQL, для обеспечения масштабируемости, производительности и безопасности;
- Использование шаблонизаторов или frontend-фреймворков (React, Vue, Angular) для создания более интерактивного и удобного интерфейса;
- Валидация и обработка ошибок на уровне сервера и клиента для повышения стабильности;
- Реализовать поиск и сортировку заметок, улучшить UX;
- Добавить резервное копирование и синхронизацию, чтобы избегать потери данных;
- Обеспечить безопасность (например, защиту от XSS, CSRF, настроить CORS и HTTPS).
Заключение
В данной статье мы подробно рассмотрели процесс создания простого веб-приложения для хранения заметок с использованием Express.js. Мы разобрали этапы планирования, настройки проекта, разработки REST API для управления заметками и создания клиентской части с помощью базовых веб-технологий. Такой подход прекрасно подходит для понимания принципов работы серверных приложений на Node.js и организации взаимодействия между клиентом и сервером.
Созданный пример можно легко адаптировать и расширять в зависимости от конкретных целей и требований проекта. Express.js остаётся одним из наиболее удобных и мощных инструментов для разработки веб-приложений и API, что делает его хорошим выбором как для начинающих, так и для опытных разработчиков.
Практические навыки, полученные при реализации данного приложения, станут отличным фундаментом для создания более сложных систем управления данными и пользовательскими сервисами.
Вот HTML-таблица с 10 LSI-запросами для статьи "Разработка веб-приложения для хранения заметок с использованием Express.js":
```html
```
Это простой HTML-код, который можно использовать для создания таблицы с запросами. Каждая ячейка таблицы содержит ссылку на соответствующий запрос.