[JavaScript] DTO в JS

Автор Сообщение
news_bot ®

Стаж: 6 лет 1 месяц
Сообщений: 27286

Создавать темы news_bot ® написал(а)
10-Июл-2021 17:31

Если DTO используются для передачи данных между слоями приложения (база данных, бизнес-логика, представления), то, по Фаулеру, это называется LocalDTO. Некоторые разработчики (включая самого Фаулера) негативно относятся к локальным DTO. Основным отрицательным моментом локального применения DTO является необходимость маппинга данных из одной структуры в другую при их передаче от одного слоя приложения к другому.Тем не менее, DTO являются важным классом объектов в приложениях и в этой статье я покажу JS-код, который на данный момент считаю оптимальным для DTO (в рамках стандартов ECMAScript 2015+).Структура данныхВо-первых, в коде должна быть отражена сама структура данных. Лучше всего это делать с использованием классов (аннотации JSDoc помогают ориентироваться в типах данных):
class ConfigEmailAuth {
    /** @type {string} */
    pass;
    /** @type {string} */
    user;
}
Это пример простой структуры данных, где каждый атрибут является примитивом. Если некоторые атрибуты сами являются структурами, то класс выглядит примерно так:
class ConfigEmail {
    /** @type {ConfigEmailAuth} */
    auth;
    /** @type {string} */
    from;
    /** @type {string} */
    host;
    /** @type {number} */
    port;
    /** @type {boolean} */
    secure;
}
Создание объектовКак правило, создание экземпляра DTO в половине случаев связано разбором имеющейся структуры данных, полученной "по проводам" с "другой стороны". Поэтому конструктор DTO получает на вход некоторый JS-объект, из которого пытается извлечь знакомые ему данные:
/**
* @param {ConfigEmailAuth|null} data
*/
constructor(data = null) {
    this.pass = data?.pass;
    this.user = data?.user;
}
В конструкторе структуры со сложными атрибутами используются конструкторы для соответствующих атрибутов:
/**
* @param {ConfigEmail} data
*/
constructor(data = null) {
    this.auth = (data?.auth instanceof ConfigEmailAuth)
        ? data.auth : new ConfigEmailAuth(data?.auth);
    this.from = data?.from || 'default@from.com';
    this.host = data?.host || 'localhost';
    this.port = data?.port || 465;
    this.secure = data?.secure || true;
}
Если какой-то атрибут представляет из себя массив, то в конструкторе его разбор выглядит примерно так:
class ConfigItems {
    /** @type {Item[]} */
    items;
    /**
     * @param {ConfigItems} data
     */
    constructor(data = null) {
        this.items = Array.isArray(data?.items)
            ? data.items.map((one) => (one instanceof Item) ? one : new Item(one))
            : [];
    }
}
Если какие-то данные должны быть сохранены в атрибуте без разбора, то это тоже возможно (хотя к DTO имеет такое себе отношение):
class SomeDto {
    /** @type {Object} */
    unknownStruct;
    /**
     * @param {SomeDto} data
     */
    constructor(data = null) {
        this.unknownStruct = data?.unknownStruct;
    }
}
МетаданныеМетаданные - это информация о коде. Метаданные позволяют отследить, где используются соответствующие атрибуты объекта:
class SaleOrder {
    /** @type {number} */
    amount;
    /** @type {number} */
    id;
}
SaleOrder.AMOUNT = 'amount';
SaleOrder.ID = 'id';
Например, при выборке данных из БД:
const query = trx.from('sale');
query.select([
    {[SaleOrder.ID]: 'saleId'},
    {[SaleOrder.AMOUNT]: 'totalAmount'},
    // ...
]);
Результирующую выборку можно напрямую передавать в конструктор SaleOrder, а затем получившийся DTO выкидывать на web в качестве ответа.РезюмеЕсли сводить воедино все три составляющих DTO (структура, конструктор, метаданные), то получается примерно такой es-модуль:
import ConfigEmailAuth from './ConfigEmailAuth.mjs';
export default class ConfigEmail {
    /** @type {ConfigEmailAuth} */
    auth;
    /** @type {string} */
    from;
    // ...
    /**
     * @param {ConfigEmail} data
     */
    constructor(data = null) {
        this.auth = (data?.auth instanceof ConfigEmailAuth)
            ? data.auth : new ConfigEmailAuth(data?.auth);
        this.from = data?.from || 'default@from.com';
        // ...
    }
}
ConfigEmail.AUTH = 'auth';
ConfigEmail.FROM = 'from';
// ...
Подобный подход позволяет извлекать знакомые подструктуры данных из больших структур (конфигурационных файлов, ответов от сервисов и т.п.), непосредственно относящиеся к текущему контексту, а IDE, за счёт аннотаций, имеет возможность помогать разработчику ориентироваться в этой подструктуре."Вот и всё, что я могу сказать об этом." (с)Информационные системы предназначены для обработки данных, а DTO (Data Transfer Object) является важным концептом в современной разработке. В “классическом” понимании DTO являются простыми объектами (без логики), описывающими структуры данных, передаваемых “по проводам” между разнесенными процессами (remote processes). Зачастую данные "по проводам" передаются в виде JSON.
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_javascript, #_ecmascript_2015, #_es6, #_dto, #_json, #_not_typescript, #_javascript
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 29-Мар 07:09
Часовой пояс: UTC + 5