Кастомные адаптеры и трансформации

Ember.js предоставляет механизмы для работы с данными через адаптеры и трансформации. Адаптеры отвечают за взаимодействие с внешними источниками данных, такими как REST API, а трансформации позволяют преобразовывать данные между их представлением в модели и форматом, который использует сервер. Создание кастомных адаптеров и трансформаций необходимо, когда стандартные решения не соответствуют специфическим требованиям проекта.

Кастомные адаптеры

Адаптеры в Ember.js используются для взаимодействия с API и других источников данных. По умолчанию Ember предоставляет несколько адаптеров, таких как RESTAdapter и JSONAPIAdapter. Однако, в некоторых случаях необходимо создать собственный адаптер, чтобы обработать нестандартные запросы, формат данных или особенности аутентификации.

Создание кастомного адаптера

Чтобы создать кастомный адаптер, нужно создать класс, который будет наследовать от ApplicationAdapter или от одного из существующих адаптеров, например, RESTAdapter. Класс кастомного адаптера может выглядеть следующим образом:

import RESTAdapter from '@ember/data/adapter/rest';

export default class CustomAdapter extends RESTAdapter {
  // Переопределение метода для настройки базового URL
  host = 'https://api.example.com';

  // Переопределение метода для обработки формата данных
  pathForType(modelName) {
    if (modelName === 'user') {
      return 'users';
    }
    return this._super(modelName);
  }

  // Кастомный метод для обработки аутентификации
  async findRecord(store, type, id, snapshot) {
    const token = localStorage.getItem('auth_token');
    const headers = {
      Authorization: `Bearer ${token}`,
    };

    const url = `${this.host}/${type.modelName}/${id}`;
    const response = await fetch(url, { headers });
    const data = await response.json();
    
    return this.serializeResponse(store, type, data, id, snapshot);
  }
}

В этом примере создается адаптер для работы с REST API, который использует кастомный URL для запроса данных, а также добавляет аутентификацию через токен.

Переопределение методов адаптера

Адаптеры предоставляют несколько методов для работы с данными:

  • findRecord(store, type, id, snapshot) — используется для получения одного ресурса по ID.
  • findAll(store, type) — используется для получения всех записей для модели.
  • createRecord(store, type, snapshot) — используется для отправки данных на сервер при создании нового ресурса.
  • updateRecord(store, type, snapshot) — используется для обновления данных на сервере.
  • deleteRecord(store, type, snapshot) — используется для удаления записи с сервера.

Все эти методы можно переопределять в кастомном адаптере, чтобы настроить работу с сервером по специфическим требованиям проекта.

Использование кастомного адаптера

Чтобы использовать кастомный адаптер, необходимо указать его в настройках модели. Например:

import Model, { attr } from '@ember-data/model';

export default class UserModel extends Model {
  @attr('string') name;
  @attr('string') email;

  // Указываем кастомный адаптер для этой модели
  static adapter = 'custom-adapter';
}

Теперь при работе с моделью UserModel будет использоваться кастомный адаптер CustomAdapter.

Кастомные трансформации

Трансформации в Ember.js используются для преобразования данных между их внутренним представлением в модели и форматом, который приходит с сервера. Например, можно преобразовывать строки в даты или числа в строковые значения. В некоторых случаях стандартные трансформации недостаточны, и требуется создание кастомных трансформаций.

Создание кастомной трансформации

Для создания кастомной трансформации необходимо создать класс, который наследуется от Transform. Кастомный класс должен реализовывать два метода: deserialize и serialize.

  • deserialize — преобразует данные из формата, полученного с сервера, в формат, который будет использован в модели.
  • serialize — преобразует данные из модели в формат, который отправляется на сервер.

Пример кастомной трансформации:

import Transform from '@ember-data/transform';

export default class CurrencyTransform extends Transform {
  // Преобразуем строку с валютой в объект с числовым значением
  deserialize(serialized) {
    if (typeof serialized === 'string') {
      return parseFloat(serialized.replace('$', ''));
    }
    return serialized;
  }

  // Преобразуем число обратно в строку с валютой
  serialize(deserialized) {
    return `$${deserialized.toFixed(2)}`;
  }
}

В этом примере трансформация используется для работы с валютой. Строка с валютой, например $100.50, преобразуется в число 100.50, и наоборот.

Использование кастомной трансформации

Чтобы использовать кастомную трансформацию в модели, необходимо указать её в типе атрибута:

import Model, { attr } from '@ember-data/model';
import CurrencyTransform from 'app/transforms/currency';

export default class ProductModel extends Model {
  @attr('currency') price;
}

Теперь поле price будет использовать кастомную трансформацию CurrencyTransform для сериализации и десериализации данных.

Комбинированное использование кастомных адаптеров и трансформаций

Часто возникает необходимость использовать как кастомные адаптеры, так и кастомные трансформации для эффективной работы с данными. Например, можно создать адаптер, который работает с нестандартным API, и использовать кастомные трансформации для корректной обработки данных, приходящих с сервера.

Пример:

import RESTAdapter from '@ember/data/adapter/rest';
import { attr } from '@ember-data/model';
import Model from '@ember-data/model';
import CurrencyTransform from 'app/transforms/currency';

export default class CustomAdapter extends RESTAdapter {
  host = 'https://api.example.com';

  async findRecord(store, type, id, snapshot) {
    const url = `${this.host}/products/${id}`;
    const response = await fetch(url);
    const data = await response.json();
    return this.serializeResponse(store, type, data, id, snapshot);
  }
}

export default class ProductModel extends Model {
  @attr('currency') price;  // Используем кастомную трансформацию для поля 'price'
}

В этом примере данные о продукте получаются с кастомного API, а поле price обрабатывается с помощью кастомной трансформации для работы с валютой.

Заключение

Кастомные адаптеры и трансформации в Ember.js позволяют гибко настраивать работу с данными, обеспечивая поддержку нестандартных API, форматов данных и специфических требований бизнеса. Создание собственных адаптеров и трансформаций позволяет повысить гибкость и масштабируемость приложения, особенно в сложных и высоконагруженных системах.