Обработка различных типов ответов

В Mithril обработка ответов от серверных API строится вокруг встроенного модуля m.request, который упрощает работу с HTTP-запросами. Основная задача — получить данные, корректно их обработать и интегрировать в компоненты интерфейса.

m.request({
    method: "GET",
    url: "/api/data"
}).then(function(result) {
    console.log(result);
}).catch(function(e) {
    console.error(e);
});

Ключевые моменты:

  • m.request возвращает Promise, что позволяет использовать цепочки then/catch или современный async/await.
  • Можно указать HTTP-метод (GET, POST, PUT, DELETE) и заголовки через headers.
  • data используется для передачи тела запроса при методах POST и PUT.

Обработка JSON-ответов

JSON является самым распространённым форматом обмена данными. Mithril автоматически преобразует JSON-ответы в объект JavaScript при помощи responseType: "json" (по умолчанию).

m.request({
    method: "GET",
    url: "/api/users",
    responseType: "json"
}).then(function(users) {
    users.forEach(user => console.log(user.name));
});

Особенности:

  • Ошибки парсинга JSON автоматически попадают в блок catch.
  • Можно указать кастомную функцию преобразования данных через unwrap:
m.request({
    method: "GET",
    url: "/api/users",
    unwrap: data => data.results
}).then(users => console.log(users));

Работа с текстовыми и бинарными данными

Для работы с текстовыми ответами используется responseType: "text":

m.request({
    method: "GET",
    url: "/api/message",
    responseType: "text"
}).then(text => console.log(text));

Для бинарных данных, таких как изображения или файлы, применяется responseType: "arraybuffer" или "blob":

m.request({
    method: "GET",
    url: "/api/image",
    responseType: "blob"
}).then(blob => {
    const imgURL = URL.createObjectURL(blob);
    document.querySelector("img").src = imgURL;
});

Обработка ошибок и статусов ответа

Mithril позволяет перехватывать ошибки как сетевого уровня, так и уровня HTTP. В catch попадают все исключения, включая неправильный JSON, ошибки сети и коды состояния, не относящиеся к диапазону 200–299.

m.request({
    method: "GET",
    url: "/api/data"
})
.then(data => console.log("Данные получены:", data))
.catch(err => {
    if (err.code === 404) {
        console.error("Ресурс не найден");
    } else {
        console.error("Произошла ошибка", err);
    }
});

Совет: Для проверки статуса удобно использовать config:

m.request({
    method: "GET",
    url: "/api/data",
    config: xhr => {
        xhr.onl oad = () => {
            if (xhr.status !== 200) {
                console.warn("Статус ответа:", xhr.status);
            }
        };
    }
});

Асинхронная обработка с async/await

Mithril полностью поддерживает синтаксис async/await, что делает код более линейным и читаемым:

async function loadUsers() {
    try {
        const users = await m.request({
            method: "GET",
            url: "/api/users"
        });
        console.log(users);
    } catch (err) {
        console.error("Ошибка загрузки пользователей", err);
    }
}

Обработка кастомных форматов

Если сервер возвращает данные в специфическом формате (например, CSV или XML), нужно использовать responseType: "text" и самостоятельно парсить содержимое:

m.request({
    method: "GET",
    url: "/api/data.csv",
    responseType: "text"
}).then(csvText => {
    const rows = csvText.split("\n").map(row => row.split(","));
    console.log(rows);
});

Интеграция с компонентами Mithril

Результаты запросов удобно сохранять в свойствах компонентов для реактивного обновления интерфейса:

const UserList = {
    users: [],
    oninit: async function() {
        this.users = await m.request({ method: "GET", url: "/api/users" });
    },
    view: function() {
        return m("ul", this.users.map(user => m("li", user.name)));
    }
};

Особенности интеграции:

  • Данные, сохранённые в свойствах компонента, автоматически вызывают перерисовку при их изменении.
  • Можно комбинировать несколько запросов с Promise.all для параллельной загрузки данных.
oninit: async function() {
    const [users, posts] = await Promise.all([
        m.request({ method: "GET", url: "/api/users" }),
        m.request({ method: "GET", url: "/api/posts" })
    ]);
    this.users = users;
    this.posts = posts;
}

Фильтрация и преобразование данных

Mithril не ограничивает обработку данных: можно использовать любые функции для фильтрации, сортировки или трансформации перед отображением:

this.activeUsers = this.users.filter(u => u.active);
this.sortedUsers = this.activeUsers.sort((a, b) => a.name.localeCompare(b.name));

Это позволяет отделить логику получения данных от логики отображения, что упрощает поддержку больших приложений.