Использование взаимозаменяемого API и кеширование результатов

Наряду с развитием технологий необходимость миграции или, по крайней мере, внедрения электронной коммерции в бизнес в настоящее время играет большую роль для компаний любого размера. Эта новая модальность направлена ​​на комфорт клиентов, потому что им не нужно выходить из дома, чтобы получить то, что они хотят. Не говоря уже о влиянии COVID на повседневную жизнь во всем мире.

Сначала эта стратегия применялась для местных или даже национальных магазинов, но в настоящее время она распространяется на всей планеты. Что это значит? Ну, кто-то может захотеть купить что-то, что продается на другом конце света, и продавец получит определенную сумму денег в валюте своей страны за купленный товар.

Хорошо, но если мы хотим, чтобы клиенты чувствовали себя комфортно, как мы сказали, зачем нам заставлять их конвертировать каждую цену, которую они видят в Интернете, вручную, чтобы действительно знать, сколько это стоит? Если мы хотим, чтобы они покупали продукты, давайте проясним цены: показывать их в валюте, которая нужна клиентам, — это хорошее начало!

Источник ставок

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

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

Базовая служба обмена валюты

Поскольку я буду разрабатывать этот пример с Django, я предлагаю вам ознакомиться с фреймворком и его языком программирования: Python.

Независимо от того, о чем ваш проект, я бы порекомендовал вам создать приложение для валюты, введя эту команду в своем терминале:

./manage.py startapp currency

Мы позаботимся о том, чтобы код, связанный с валютой, хранился в одном месте.

Мы хотим иметь класс, который обрабатывает преобразование суммы из одной валюты в другую, используя ресурс выбранных курсов, о котором мы упоминали ранее. Давайте посмотрим, как работает Exchange Rates API!

Выполнив следующий вызов API, мы получим последние справочные курсы иностранных валют:

GET https://api.exchangeratesapi.io/latest?base=EUR HTTP/1.1
{
  "rates": {
    "CAD": 1.5243,
    "HKD": 8.4286,
    "ISK": 158.3,
    "PHP": 54.545,
    "DKK": 7.4556,
    "HUF": 353.58,
    "CZK": 27.408,
    "AUD": 1.6687,
    "RON": 4.8353,
    "SEK": 10.5843,
    "IDR": 16092.26,
    "INR": 81.8825,
    "BRL": 6.3606,
    "RUB": 79.5893,
    "HRK": 7.5705,
    "JPY": 116.28,
    "THB": 34.844,
    "CHF": 1.0528,
    "SGD": 1.538,
    "PLN": 4.5636,
    "BGN": 1.9558,
    "TRY": 7.5861,
    "CNY": 7.7102,
    "NOK": 10.938,
    "NZD": 1.7983,
    "ZAR": 19.919,
    "USD": 1.0875,
    "MXN": 26.2304,
    "ILS": 3.819,
    "GBP": 0.88245,
    "KRW": 1331.08,
    "MYR": 4.704
  },
  "base": "EUR",
  "date": "2020-05-13"
}

Как мы используем эту информацию?

По сути, наш класс должен иметь метод, который будет получать:

  • Базовая валюта, которая является валютой по умолчанию для нашей электронной торговли.
  • Конвертируемая валюта, которая является валютой клиента.
  • Сумма, подлежащая конвертации (из базовой валюты в конвертируемую валюту).

Назовем этот метод convert. Если обе валюты одинаковы, данная сумма будет возвращена как есть, тогда конвертация не требуется. В противном случае он выполнит API-вызов к выбранному ресурсу ставок, получив соответствующую ставку и выполнив правильные математические операции для получения преобразованного результата. Это будет выглядеть примерно так:

Использование джанго-денег

Существует хорошая библиотека Django под названием django-money, которая упрощает манипулирование деньгами на всем протяжении вашего приложения, поскольку инкапсулирует сумму и валюту в один объект класса Money, помимо других интересных вещей. . Это звучит идеально для нашей службы обмена валюты. Давайте включим в него понятие денег!

Как видите, были внесены некоторые изменения:

  • Вместо получения суммы, базовой валюты и конвертированной валюты теперь мы будем получать только денежный объект и валюту. Из денежного объекта мы можем извлечь сумму и базовую валюту.
  • Чтобы сделать то, что мы объяснили в предыдущем пункте, мы должны убедиться, что параметр money на самом деле является экземпляром класса Money. Вот почему мы проверяем его в начале и вызываем исключение, если оно не удовлетворяет нашим требованиям.
  • Параметр валюты может быть либо строкой, либо объектом валюты (из django-money), но чтобы использовать его для доступа к ответу о курсах, мы должны убедиться, что все валюты приведены к строкам.
  • Вместо того, чтобы возвращать сумму, мы теперь возвращаем денежный объект, который более согласован с новой реализацией.

Кэширование результатов

Большой! У нас уже есть служба обмена валюты, которая работает с внешним API, который предоставляет нам курсы валют. Пришло время пойти немного дальше и сделать его лучше.

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

Я убедил тебя? Как насчет кэширования ставок на определенное время, чтобы избежать этих вызовов API?

Я решил использовать Redis для кэширования своих данных. Это хранилище структур данных в памяти, используемое в качестве базы данных, кэша и брокера сообщений.

Если вы используете Docker и Docker Compose для запуска своего приложения, вы должны поместить это в свой docker-compose.yml:

version: "3.1"
services:
  redis:
    image: redis:6.0-rc1-alpine
    restart: always
    ports:
      - "6379:6379"

И в вашем settings.py:

CACHES = {
    "default": {
        "BACKEND": "redis_cache.cache.RedisCache",
        "LOCATION": "redis://redis:6379/1",
        'TIMEOUT': 86400,
        "OPTIONS": {
            "CLIENT_CLASS": "redis_cache.client.DefaultClient",
        }
    }
}

Примечание. Имейте в виду, что если вы используете Redis локально, вам следует изменить конфигурацию на эту "LOCATION": "redis://127.0.0.1:6379/1".

И, наконец, наш сервис обмена валюты будет выглядеть примерно так:

Когда нам нужно получить доступ к скорости, мы сначала проверим, находится ли эта информация в кеше. Если нет, мы сделаем вызов API и установим кеш для предстоящих запросов.

И последнее, но не менее важное: тестирование

Всегда полезно написать несколько модульных тестов, чтобы проверить, что написанный нами код работает нормально. Посмотрим, как будут выглядеть наши тесты!

Для этой службы обмена валюты есть два сложных фактора, с которыми мы должны справиться:

Кэширование в тестах

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

Для этого нам придется переопределить кеш Redis с помощью кеша локальной памяти, который использует нашу локальную память. Мы не используем фиктивный кэш, потому что на самом деле хотим, чтобы он сохранял скорости для их проверки.

@override_settings(CACHES={
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
    }
})

Обратите внимание, что нам придется очищать кеш после каждого теста, чтобы очистить его для предстоящих тестов.

Имитация вызовов API

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

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

@responses.activate

У нас будет константа с именем EUR_BASE_RESPONSE, которая хранит некоторые скорости, всегда соблюдая структуру ответа API, которые будут переданы объекту ответов для имитации фактического ответа.

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

Подведение итогов

Мы создали гибкий сервис обмена валюты, который конвертирует деньги из одной валюты в другую и позволяет нам легко менять источник курсов валют. В дополнение к этому, он кэширует эти скорости, чтобы сделать наше приложение быстрее. Круто, да? 😉

Обратите внимание, что если вы используете django-money, вы можете расширить его сервер обмена по умолчанию, чтобы создать этот сервис, или, возможно, вы можете использовать существующую библиотеку конвертации. В этом посте я хотел показать шаг за шагом разъяснение некоторых понятий, но не стесняйтесь использовать то, что вам больше подходит!

Большое спасибо за чтение этого поста, и я надеюсь, что он поможет вам в ваших проектах. Следите за мной, чтобы не пропустить следующие публикации, и я желаю вам удачи и счастливого кодирования!