JS Tower
Node.jsМодуль 4: HTTP и Express

Обработка данных

JSON, формы, загрузка файлов

Цель урока

В этом уроке ты научишься:

  • Обрабатывать JSON данные
  • Работать с формами
  • Загружать файлы

JSON данные

Получение JSON

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

// Включаем парсинг JSON
app.use(express.json({ limit: '10mb' }));

app.post('/api/users', (req, res) => {
  const { name, email } = req.body;
  
  if (!name || !email) {
    return res.status(400).json({ error: 'Name and email required' });
  }
  
  res.status(201).json({ id: 1, name, email });
});

Отправка JSON

app.get('/api/data', (req, res) => {
  // Автоматически устанавливает Content-Type: application/json
  res.json({
    success: true,
    data: [1, 2, 3],
    timestamp: new Date()
  });
});

Формы (URL-encoded)

// Включаем парсинг форм
app.use(express.urlencoded({ extended: true }));

app.post('/login', (req, res) => {
  const { username, password } = req.body;
  
  // Обработка данных формы
  res.json({ username });
});

HTML форма

<form action="/login" method="POST">
  <input name="username" type="text" />
  <input name="password" type="password" />
  <button type="submit">Войти</button>
</form>

Загрузка файлов (Multer)

Установка

npm install multer

Базовая настройка

const multer = require('multer');

// Хранение в памяти
const upload = multer({ storage: multer.memoryStorage() });

// Хранение на диске
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, 'uploads/');
  },
  filename: (req, file, cb) => {
    const uniqueName = `${Date.now()}-${file.originalname}`;
    cb(null, uniqueName);
  }
});

const uploadDisk = multer({ storage });

Один файл

app.post('/upload', upload.single('file'), (req, res) => {
  if (!req.file) {
    return res.status(400).json({ error: 'No file uploaded' });
  }
  
  console.log(req.file);
  // {
  //   fieldname: 'file',
  //   originalname: 'photo.jpg',
  //   mimetype: 'image/jpeg',
  //   size: 12345,
  //   buffer: <Buffer ...>  // если memoryStorage
  //   path: 'uploads/...'   // если diskStorage
  // }
  
  res.json({ filename: req.file.originalname });
});

Несколько файлов

// Несколько файлов в одном поле
app.post('/upload', upload.array('files', 10), (req, res) => {
  console.log(req.files);  // массив файлов
  res.json({ count: req.files.length });
});

// Разные поля
app.post('/upload', upload.fields([
  { name: 'avatar', maxCount: 1 },
  { name: 'photos', maxCount: 5 }
]), (req, res) => {
  console.log(req.files.avatar);
  console.log(req.files.photos);
  res.json({ success: true });
});

Фильтрация файлов

const upload = multer({
  storage: multer.diskStorage({
    destination: 'uploads/',
    filename: (req, file, cb) => {
      cb(null, `${Date.now()}-${file.originalname}`);
    }
  }),
  limits: {
    fileSize: 5 * 1024 * 1024  // 5MB
  },
  fileFilter: (req, file, cb) => {
    const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
    
    if (allowedTypes.includes(file.mimetype)) {
      cb(null, true);
    } else {
      cb(new Error('Invalid file type'), false);
    }
  }
});

Валидация данных

С Joi

npm install joi
const Joi = require('joi');

const userSchema = Joi.object({
  name: Joi.string().min(2).max(50).required(),
  email: Joi.string().email().required(),
  age: Joi.number().integer().min(18).max(120),
  role: Joi.string().valid('user', 'admin').default('user')
});

app.post('/users', (req, res) => {
  const { error, value } = userSchema.validate(req.body);
  
  if (error) {
    return res.status(400).json({ 
      error: error.details[0].message 
    });
  }
  
  res.json(value);
});

С express-validator

npm install express-validator
const { body, validationResult } = require('express-validator');

app.post('/users', 
  body('email').isEmail().normalizeEmail(),
  body('password').isLength({ min: 6 }),
  body('name').trim().notEmpty(),
  (req, res) => {
    const errors = validationResult(req);
    
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }
    
    res.json(req.body);
  }
);

Практика

Задание 1: Загрузка аватара

Задача: Создай endpoint для загрузки аватара пользователя.

Решение:

const multer = require('multer');
const path = require('path');

const avatarStorage = multer.diskStorage({
  destination: 'uploads/avatars/',
  filename: (req, file, cb) => {
    const ext = path.extname(file.originalname);
    cb(null, `avatar-${req.params.userId}${ext}`);
  }
});

const uploadAvatar = multer({
  storage: avatarStorage,
  limits: { fileSize: 2 * 1024 * 1024 },
  fileFilter: (req, file, cb) => {
    if (file.mimetype.startsWith('image/')) {
      cb(null, true);
    } else {
      cb(new Error('Only images allowed'), false);
    }
  }
});

app.post('/users/:userId/avatar', 
  uploadAvatar.single('avatar'),
  (req, res) => {
    res.json({ path: req.file.path });
  }
);

Проверь себя

  1. Как включить парсинг JSON в Express?
  2. Как ограничить размер загружаемого файла?
  3. Как валидировать email с Joi?