Как рендерить ошибки на Node.js с Backbone

Короткий ответ: Node.js-сервер не должен “рисовать” ошибку для Backbone напрямую. Сервер должен вернуть корректный HTTP-статус и JSON с понятным текстом ошибки, а Backbone должен поймать ошибку в error-callback и отрисовать сообщение во View

Backbone — старая, но еще встречающаяся связка в проектах. Главная путаница здесь в слове “рендерить”: Express отвечает за HTTP-ответ, а Backbone отвечает за отображение в браузере. Если смешать эти роли, код быстро превращается в набор частных костылей

Какой формат ошибки отдавать с Node.js

Для API удобен единый формат

{
  "message": "Название обязательно",
  "fields": {
    "name": "Введите название"
  }
}

message — общий текст ошибки, fields — ошибки конкретных полей формы. Такой JSON удобно показать в Backbone View

Express-роут с ошибкой валидации

Пример сервера

const express = require("express");

const app = express();

app.use(express.json());

app.post("/api/tasks", (req, res) => {
  const { title } = req.body;

  if (!title || title.trim() === "") {
    res.status(422).json({
      message: "Задачу нельзя сохранить",
      fields: {
        title: "Введите название задачи"
      }
    });
    return;
  }

  res.status(201).json({
    id: Date.now(),
    title
  });
});

app.listen(3000, () => {
  console.log("Server started");
});

Статус 422 подходит для ошибки валидации. Для неизвестной серверной ошибки используйте 500, для отсутствующей записи — 404, для запрета доступа — 403

Middleware для серверных ошибок

Если ошибка произошла глубже в коде, ее лучше обрабатывать централизованно

app.use((error, req, res, next) => {
  console.error(error);

  res.status(500).json({
    message: "Внутренняя ошибка сервера"
  });
});

Не отдавайте пользователю stack trace, SQL-запросы, токены и внутренние детали. В логах это может быть полезно, в браузере — нет

Backbone Model

Модель может быть простой

const Task = Backbone.Model.extend({
  urlRoot: "/api/tasks"
});

При сохранении Backbone отправит данные на сервер

const task = new Task({
  title: ""
});

Если сервер вернет 422, Backbone вызовет обработчик ошибки

Backbone View с отображением ошибок

Пример View

const TaskFormView = Backbone.View.extend({
  el: "#task-form",

  events: {
    "submit": "onSubmit"
  },

  onSubmit(event) {
    event.preventDefault();

    const title = this.$("[name=title]").val();
    const task = new Task({ title });

    this.clearErrors();

    task.save(null, {
      success: () => {
        this.$(".result").text("Задача сохранена");
      },
      error: (model, xhr) => {
        const response = xhr.responseJSON || {};
        this.renderErrors(response);
      }
    });
  },

  renderErrors(error) {
    this.$(".form-error").text(error.message || "Не удалось сохранить данные");

    if (error.fields && error.fields.title) {
      this.$(".title-error").text(error.fields.title);
    }
  },

  clearErrors() {
    this.$(".form-error").text("");
    this.$(".title-error").text("");
    this.$(".result").text("");
  }
});

HTML может выглядеть так

<form id="task-form">
  <div class="form-error"></div>

  <label>
    Название
    <input name="title" type="text">
  </label>
  <div class="title-error"></div>

  <button type="submit">Сохранить</button>
  <div class="result"></div>
</form>

Теперь ошибка приходит с Node.js, но рендерится на стороне Backbone

Почему не стоит возвращать готовый HTML ошибки

Сервер может вернуть

<div class="error">Введите название</div>

Но для Backbone-приложения это обычно хуже, чем JSON. Клиенту сложнее управлять состоянием формы, подсветкой полей и повторным рендером. JSON дает клиенту данные, а View решает, как именно их показать

Исключение — если проект изначально серверный и Backbone используется только для маленьких интерактивных блоков. Тогда можно отдавать HTML-фрагменты, но это уже другая архитектура

Как обработать ошибку fetch

Для загрузки данных принцип такой же

collection.fetch({
  success: () => {
    view.render();
  },
  error: (collection, xhr) => {
    const response = xhr.responseJSON || {};
    view.renderError(response.message || "Не удалось загрузить данные");
  }
});

Сервер должен вернуть нормальный статус и JSON

app.get("/api/tasks", (req, res) => {
  res.status(500).json({
    message: "Не удалось загрузить задачи"
  });
});

Мини-практика

Сделайте форму с одним полем title. На сервере верните 422, если поле пустое. В Backbone View покажите общий текст ошибки над формой и отдельный текст под полем. Затем добавьте успешный сценарий и очищайте ошибки перед новой отправкой

Так вы сразу увидите правильное разделение: Express проверяет данные, Backbone показывает результат пользователю

Частые ошибки

Сервер возвращает 200 даже при ошибке Backbone не попадет в error-callback, если HTTP-статус успешный. Для ошибки валидации используйте 422

Клиент ждет responseJSON, а сервер отдает текст Возвращайте res.json(...), чтобы Backbone мог прочитать xhr.responseJSON

Показывают внутреннюю ошибку пользователю Пользователю нужен понятный текст, разработчику — подробный лог на сервере

Рисуют ошибку в нескольких местах без очистки Перед новой отправкой формы очищайте старые сообщения, иначе интерфейс будет показывать устаревшие ошибки

Что почитать дальше по Node.js

Если нужен общий маршрут по теме, откройте рубрику Node.js. Для соседних задач пригодятся эти разборы:

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x