Созданы солнечные панели, которые даже ночью вырабатывают заметные объёмы энергии

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

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

Тесты панелей данного типа показали, что с одного квадратного метра можно получить до 50 мВт мощности в безоблачную ночь. За счет оптимизации конструкции и других модернизаций данный показатель можно увеличить до 1-2 Вт. Этого уже вполне достаточно для стабильной работы определенных электроприборов.

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

В России создан полностью отечественный сервер Storm 3450E3R на «Эльбрусах»

Компания Depo Computers (Россия) сообщила о разработке отечественного сервера Depo Storm 3450E3RU. Полноразмерный сервер полностью совместим с отечественной ОС «Альт Сервер». В основе аппаратной части лежат российские процессоры семейства «Эльбрус». Производство уже запущено в городе Красногорск.

Разработчики отметили, что Depo Storm 3450E3RU полностью протестирован на совместимость с системой «Альт Сервер» версии 10. Аппаратно-программный комплект можно использовать как систему хранения данных, сервер приложений, а также для решения других задач в корпоративном секторе.

Представители компании также отметили, что до перехода на «Альт Сервер» сервер функционировал на ОС «Эльбрус». В дальнейшем планируется провести сертификацию с ОС Astra Linux.

Depo Storm 3450E3RU имеет корпус 2U для использования в стандартной стойке. Основные аппаратные узлы – отечественные. Материнская плата разработана в компании Depo, процессор «Эльбрус» - разработка компании МЦСТ. Платформа «Альт Сервер», основанная на ядре Linux, также разработана в России. Это позволяет использовать новый сервер как элемент импортозамещения, в том числе и как полноценный аналог устройств на серверных чипах Intel и AMD.

Depo Storm 3450E3RU использует два чипа «Эльбрус-8СВ». Процессоры выполнены по 28-нанометровой технологии, имеют 8 ядер и работают на частоте 1,5 ГГц. Рассчитаны чипы как раз на использование в многопроцессорных серверах и рабочих станциях. Они также могут использоваться в специализированных бортовых вычислителях, требующих высокой скорости обработки данных.

Процессор также комплектуется 16 МБ кэша третьего уровня, есть поддержка ОЗУ DDR4-2400 (4 контроллера). Чип имеет размеры 59,5х43х4,6 мм, корпус FCBGA. Официальный анонс состоялся в начале 2019 года, старт серийного производства – 2020 год.

Максимальное потребление отдельного CPU – 110 Вт, поэтому Depo Storm 3450E3RU комплектуется сразу двумя блоками питания, каждый 800 Вт. Такое значительный запас мощности сделан, чтобы обеспечить стабильное питание всей дисковой подсистеме. Максимально можно смонтировать 12 накопителей NL-SAS/SAS (2,5 или 3,5 дюйма). В задней части предусмотрен дополнительный отсек для двух накопителей формата 2,5 дюйма с интерфейсом SATA и поддержкой горячей замены.

На основной плате размещены 8 слотов DDR4 ECC. За обработку графики отвечает интегрированный  модуль Aspeed AST2500. При использовании сервера как систему хранения данных, накопители можно объединять в различные версии массивов RAID: 0/1/5/6/7.3/10/50/60/70.

Доступно 4 гигабитных порта Ethernet, один порт USB 2.0, а также по одному разъему PCI-E х8 2.0, х4 2.0, х16 2.0. Дополнительно установлены разъемы COM, VGA и выделенный порт управления IPMI 2.0 (ASPEED AST2500). На лицевую панель выведены только порты VGA и USB 3.0, остальные – на тыльной стороне.

Платформа «Альт Сервер» входит в состав семейства ОС «Альт», которое развивают специалисты компании «Базальт СПО».  Десятая версия системы распространяется с набором прикладного ПО. Это позволяет устанавливать ее на различные типы серверов, включая серверы СУБД, веб-серверы, системы хранения данных.

«Спящие» вкладки в браузере Microsoft Edge теперь позволят экономить больше ресурсов компьютера

Специалисты Microsoft продолжают работать над улучшением обозревателя Edge. На этот раз изменения коснулись работы так называемых «спящих» вкладок. Это позволит приложению экономить ресурсы системы.

Ранее корпорация анонсировала стабильную версию Edge 100, в которой среди обновлений также была обновленная функция «спящих» вкладок. Пользователи получили возможность больше вкладок переводить в спящий режим. Также обозреватель теперь отображает в реальном времени, сколько ресурсов было сэкономлено данным инструментом.

По информации разработчиков, была изменена сама схема перевода вкладок браузера в спящий режим. В более ранних версиях Edge вкладка не переводилась в спящий режим, если активная и фоновая страницы использовали один экземпляр приложения. Теперь данное ограничение отсутствует.

По информации разработчиков, теперь приложение может отправлять в спящий режим на 8% больше вкладок, при этом каждая такая вкладка экономит до 85% ОЗУ и до 99% ресурсов процессора. Это позволяет оптимизировать работу ОС в целом, перераспределяя аппаратные ресурсы. Для анализа освобожденных ресурсов достаточно открыть главное меню (иконка с тремя точками) и выбрать пункт «Производительность».

Twitter экспериментирует с «отменой упоминаний»

Представители Twitter подтвердили, что экспериментируют с функцией, которая позволит пользователям отменять упоминания (unmentioning). Новый инструмент позволит пользователям удалять себя из нежелательных обсуждений.

В сообщении также присутствует иллюстрация, описывающая принцип работы нового инструмента. На странице уведомлений, напротив упоминания ника, доступна опция «Покинуть это обсуждение». При выборе данной опции система предложит три варианта: отключение упоминаний, деактивация дальнейших упоминаний в данном обсуждении или отключение уведомлений о следующих публикациях.

Отключение оповещений может быть полезным, если пользователю становиться неприятным развитие обсуждения, либо он столкнулся с угрозами – есть возможность просто отстраниться от дискуссии.

На смарт-телевизорах Samsung можно будет покупать и продавать NFT

Корпорация Samsung при участии Nifty Gateway (популярная NFT-платформа) работает над созданием приложения для работы с невзаимозаменяемыми токенами (NFT). Решение планируется внедрить в новую линейку с устройствами премиум-класса.

Пользователи получат возможность добавлять в приложение свои аккаунты Nifty Gateway, а также приобретать токены при помощи дебетовых карт. Как отметил сооснователь сервиса Гриффин Кок, инициатива преследует сразу две цели: заинтересовать коллекционеров цифрового искусства, а также привлечь новых пользователей в NFT.

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

Напомним, ранее нескольку крупных социальных ресурсов заявили о внедрении поддержки технологии NFT. Собственное решение разрабатывает «ВКонтакте», в Twitter уже можно использовать аватары, связанные с токенами.

Django — базовые принципы работы с API

Разобраться с базовыми принципами работы с API вам поможет наш простой Django-проект Kittygram: управление котиками.

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

Обратите внимание на библиотеку djangorestframework, именно она поможет быстро и гибко настроить API проекта. Загляните в файл настроек settings.py: проверьте, что приложение cats и библиотека rest_framework добавлены в INSTALLED_APPS.

А что внутри?

В Kittygram описана простая модель — Cat. В ней есть три поля:

# kittygram/cats/models.py
class Cat(models.Model):
    name = models.CharField(max_length=16)
    color = models.CharField(max_length=16)
    birth_year = models.IntegerField(blank=True, null=True)

    def __str__(self):
        return self.name 

В файле urls.py настроена обработка адреса cats/: запросы к этому URL направляются во view-функцию cat_list() приложения cats:

# kittygram/kittygram/urls.py
from django.urls import path

from .views import cat_list

urlpatterns = [
    path('cats/', cat_list, name='cat_list'),
] 

Файл views.py содержит единственную view-функцию cat_list(). Обратите внимание на декоратор @api_view, именно он настраивает обычную view-функцию для работы с API: например, в нём указываются типы запросов, которые должна обрабатывать view-функция. В следующем уроке мы разберёмся, что это за декоратор и чем ещё он хорош.

# kittygram/cats/views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status

from .models import Cat
from .serializers import CatSerializer

# View-функция cat_list() будет обрабатывать только запросы GET и POST, 
# запросы других типов будут отклонены,
# так что в теле функции их можно не обрабатывать
@api_view(['GET', 'POST'])
def cat_list(request):
    if request.method == 'POST':
        serializer = CatSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    cats = Cat.objects.all()
    serializer = CatSerializer(cats, many=True)
    return Response(serializer.data) 

Откройте в редакторе файл serializers.py, там описан сериализатор CatSerializer:

# kittygram/cats/serializers.py

from rest_framework import serializers

from .models import Cat


class CatSerializer(serializers.ModelSerializer):
    class Meta:
        model = Cat
        fields = '__all__' 

Сериализатор CatSerializer связывает модель и view-класс: он берёт информацию о типах данных из модели, указанной в поле model. Остаётся только указать в fields те поля, которые надо сериализовать, — и система заработает.

Проверяем работу Kittygram

После развёртывания проект Kittygram полностью готов к работе. Запустите его и сделайте к нему запрос через Postman.

  1. Запустите приложение Kittygram командой python manage.py runserver.
  2. Запустите приложение Postman, в качестве целевого URL укажите http://127.0.0.1:8000/cats/.
  3. Отправьте GET-запрос.

В ответ вернётся пустой JSON-объект. Это нормально, ведь в базе данных пока пусто:

Первый котик в Kittygram

Чтобы создать в БД первую запись с котиком, выполните POST-запрос к проекту и передайте поля namecolor и birth_year:

Обратите внимание, что поля нужно передавать в теле (англ. body) POST-запроса. А в Postman в соответствующем разделе должны быть выбраны опции raw и JSON.

Проверьте ответ: если запрос обработан корректно, должен вернуться статус-код 201 Created и JSON с только что созданным объектом.

Получилось? Отлично!

Сделайте ещё один POST-запрос, создайте запись для второго котика.

Повторно выполните GET-запрос на тот же URL, в ответ вам вернётся список из существующих в базе данных записей.

Время делать ошибки: 400 Bad Request

Проверьте, что будет, если передать данные в неправильном формате: например, вместо целочисленного значения в поле birth_year передайте данные в формате месяц.год.

При валидации данных сериализатор обнаружит ошибку, и в ответ вернётся вот такой JSON:

{
    "birth_year": [
        "A valid integer is required."
    ]
} 

Обратите внимание на статус-код ответа: 400 Bad Request. Поле birth_year ожидает данные в формате Integer (целое число), а полученные в запросе данные можно привести только к float. В результате запрос не прошёл валидацию и запись не была создана.

Измените запрос: укажите год в формате Integer и повторите попытку. На этот раз всё должно пройти гладко.

Ошибка 405 Method Not Allowed

В декораторе view-функции cat_list() указано, что она должна обрабатывать запросы GET или POST: можно только создавать и запрашивать данные.

@api_view(['GET', 'POST'])
def cat_list(request):
    ... 

При попытке удалить запись методом DELETE вернётся сообщение об ошибке: 405 Method Not Allowed.

{
    "detail": "Method \"DELETE\" not allowed."
} 

Настройка полей в ответе

При запросе к API пользователю не понадобится id котика. Хорошо бы убрать это поле из JSON-ответа.Список полей, передаваемых в ответ, описывается в сериализаторе, в поле fields. Вместо записи fields = '__all__' явно перечислите обрабатываемые поля.

# Обновлённый kittygram/cats/serializers.py
from .models import Cat
from rest_framework import serializers


class CatSerializer(serializers.ModelSerializer):
    class Meta:
        model = Cat
        fields = ('id', 'name', 'color', 'birth_year') 

Сделайте GET-запрос на эндпоинт http://127.0.0.1:8000/cats/ и проверьте, что всё работает и ответ не изменился.Уберите id из списка полей, и ваш API перестанет отправлять ненужные данные клиенту.

# Обновлённый kittygram/cats/serializers.py
from .models import Cat
from rest_framework import serializers


class CatSerializer(serializers.ModelSerializer):
    class Meta:
        model = Cat
        fields = ('name', 'color', 'birth_year') 

Ещё раз сделайте GET-запрос для получения полного списка котиков и посмотрите, как изменилась выдача:

...
{
    "name": "Леопольд",
    "color": "Рыжий",
    "birth_year": 1975
}
... 

Отлично! Мы избавились от ненужного поля в выдаче.

Сериализаторы в Django

С этого урока вы начнёте писать REST API на основе Django REST framework (DRF). В общем виде задача для RESTful API выглядит так: в БД проекта есть данные, и мы хотим управлять ими посредством запросов; архитектура API должна базироваться на принципах REST.

Самый простой API должен реализовать как минимум шесть типичных действий для выбранных моделей:

  • создание нового объекта;
  • получение информации об одном объекте;
  • удаление объекта;
  • полное замещение существующего объекта;
  • изменение одного или нескольких полей объекта;
  • получение списка объектов.

Интерфейс для людей: веб-страницы

Ранее в ваших Django-проектах обработка запросов происходила так:

  • в приложение прилетает HTTP-запрос,
  • запрос передаётся в urls.py и, в зависимости от запрошенного адреса, отправляется в соответствующую view-функцию или view-класс;
  • view-функция или view-класс при необходимости взаимодействует с базой данных;
  • функция render передаёт данные, сгенерированные во View, в HTML-шаблон и создаёт HTML-страницу;
  • готовая HTML-страница отдаётся в качестве HTTP-ответа.

В результате клиент получает информацию из БД, неразрывно связанную с её оформлением: данные встроены в HTML-страницу, а HTML — это способ представить информацию в формате, удобном для чтения человеком: это «интерфейс для людей».

Интерфейс для машин: JSON

В свою очередь API, это интерфейс для программ, и он работает с чистыми данными, получает и передаёт их в машиночитаемом виде. Информацию, с которой работает API, обрабатывают программы, следовательно, HTML-шаблоны в этой системе не требуются.

При работе API данные должны преобразовываться из формата в формат: информация приходит в полях запроса; эти данные должны быть преобразованы в объекты Python и обработаны, а ответ должен вернуться (согласно архитектуре REST) в формате JSON.

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

Сериализация

Для начала определим, как именно должны трансформироваться данные. Для экспериментов создадим объект класса Post: по своему смыслу он будет похож на модель Post в Yatube, но это будет не модель, а обычный Python-класс с тремя полями — author (строка), text (строка) и pub_date (дата).

from datetime import datetime

# Класс Post
class Post():
    def __init__(self, author, text, pub_date=None):
        self.author = author
        self.text = text
        self.pub_date = pub_date or datetime.now()


# Экземпляр класса Post
post = Post(author='Робинзон Крузо', 
            text='23 ноября. Закончил работу над лопатой и корытом.',
            pub_date ='1659-11-23T18:02:33.123543Z'
            ) 

Этот объект можно представить в виде JSON:

# Экземпляр класса в формате JSON
{
    "author": "Робинзон Крузо",
    "text": "23 ноября. Закончил работу над лопатой и корытом.",
    "pub_date": "1659-11-23T18:02:33.123543Z"
} 

Десериализация и валидация

Преобразование данных требуется не только для создания ответа, но и при получении запроса к API.Данные из запроса необходимо проверить на соответствие ожиданиям (валидировать, как при работе с формами) и затем преобразовать в Python-объекты. Трансформация данных из запроса в объекты Питона называется десериализацией.Что будет, если в запросе пришёл такой JSON?

# JSON-объект
{
    "author": 1,
    "text": "23 ноября. Закончил работу над лопатой и корытом.",
    "pub_date": "1659-11-23T18:02:33.123543Z"
} 

API должен сериализовать его в экземпляр класса Post, но сперва — валидировать.

В поле author ожидалась строка, но в объекте JSON пришло целочисленное значение. Это значение не соответствует ожиданиям, JSON не пройдёт валидацию и не будет конвертирован, Python-объект не будет создан. Валидация спасла сервис от ошибки.

И что в результате?

На практике весь цикл работы API, от получения запроса до отправки ответа, выглядит так:

  • получение запроса,
  • валидация данных из запроса,
  • десериализация (преобразование данных из запроса в Python-объекты),
  • обработка запроса (какие-то манипуляции с полученными данными или запрос к БД),
  • сериализация данных, отправляемых клиенту (из Python в JSON),
  • отправка ответа.

Классы-сериализаторы

В Django REST framework есть классы, которые способны выполнить все три необходимые операции с данными: валидировать, десериализовать запрос и сериализовать ответ. Эти классы называются сериализаторы.

Сериализаторы могут работать с моделями Django и с обычными Python-классами.

  • Для работы с обычными Python-классами сериализаторы наследуют от класса Serializer.
  • Сериализаторы, работающие с моделями, наследуются от ModelSerializer.

Эти классы чем-то схожи с Form и ModelForm: при получении запроса с их помощью данные валидируют и конвертируют в Python-объекты, а при ответе преобразуют возвращаемые данные в необходимый формат.

Первый сериализатор

Сериализуем пост Робинзона: напишем класс-сериализатор PostSerializer и с его помощью конвертируем объект класса Post в JSON.PostSerializer будет наследоваться от класса Serializer (ведь Post — это не модель, а обычный класс Python).

В сериализаторе PostSerializer опишем:

  • поля, которые должны вернуться в ответе;
  • типы этих полей: чтобы сериализатор мог правильно конвертировать данные, он должен «знать», какие типы данных ожидает то или иное поле класса Post;
  • параметры этих полей (например, максимальную и минимальную длину строки для CharField).
# Класс Post
class Post():
    def __init__(self, author, text, pub_date=None):
        self.author = author
        self.text = text
        self.pub_date = pub_date or datetime.now()


# Создаём сериализатор, наследник предустановленного класса Serializer
class PostSerializer(serializers.Serializer):
    # Описываем поля и их типы
    author = serializers.CharField(max_length=200)
    text = serializers.CharField(max_length=5000)
    pub_date = serializers.DateTimeField() 

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

По умолчанию сериализатор будет искать в переданном объекте поля с такими же названиями, как и его собственные. Эти же имена послужат ключами в результирующем словаре после конвертации данных.

Если имена полей в сериализаторе и в объекте, переданном в сериализатор, будут различаться — возникнет ошибка AttributeError.

Полный перечень типов полей для сериализаторов доступен в официальной документации.

Теперь передадим в конструктор сериализатора Python-объект, сериализуем его и на выходе получим JSON.

Преобразование Python-объекта в JSON происходит в два шага: сначала сериализатор из данных объекта создаст Python-словарь (он будет доступен через serializer.data), а затем этот словарь будет преобразован непосредственно в JSON.

В коде сериализация будет выглядеть так:

from datetime import datetime
from rest_framework import serializers
# Импорт класса, который конвертирует Python-словарь в JSON
from rest_framework.renderers import JSONRenderer


class Post():
    def __init__(self, author, text, pub_date=None):
        self.author = author
        self.text = text
        self.pub_date = pub_date or datetime.now()


# Создаём сериализатор, наследник предустановленного класса Serializer
class PostSerializer(serializers.Serializer):
    # Описываем поля и их типы
    author = serializers.CharField(max_length=200)
    text = serializers.CharField(max_length=5000)
    pub_date = serializers.DateTimeField()


# Создаём объект класса Post
post = Post(author='Робинзон Крузо', 
            text='23 ноября. Закончил работу над лопатой и корытом.',
            pub_date ='1659-11-23T18:02:33.123543Z'
            )

# Создаём экземпляр сериализатора PostSerializer
# Передаём в него объект класса Post
serializer = PostSerializer(post)

# serializer.data содержит Python-словарь:
# {'author': 'Робинзон Крузо', 'text': '23 ноября. Закончил работу над лопатой и корытом.', 'pub_date': '1659-11-23T18:02:33.123543Z'}

# Рендерим JSON из Python-словаря:
json_object = JSONRenderer().render(serializer.data)

# Готово! Переменная json_object содержит JSON, созданный из Python-словаря 

Работа с моделями: ModelSerializer

Чаще всего работа с данными в Django осуществляется через модели, и в таких случаях сериализатор наследуется от класса ModelSerializer.

При создании такого сериализатора во внутреннем классе Meta нужно указать модель, с которой должен работать сериализатор, и список тех полей модели, которые нужно сериализовать. С внутренним классом Meta вы уже встречались при работе с ModelForm, в ModelSerializer его назначение аналогично.

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

Сериализатор для модели Comment:

...

class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    text = models.TextField()
    created = models.DateTimeField("created", auto_now_add=True)

...

class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        # Указываем поля модели, с которыми будет работать сериализатор 
        # (поля модели, не указанные в этом списке, сериализатор будет игнорировать).
        # Для перечисления полей можно использовать список или кортеж.
        fields = ('id', 'post', 'author', 'text', 'created') 

Чтобы сериализатор работал со всеми полями модели без исключения, вместо перечисления полей в fields можно указать fields = '__all__'.

Вместо fields можно применить настройку exclude: в этом случае сериализатор будет работать со всеми полями модели, за исключением перечисленных.

Хорошая практика — явно указывать все поля, которые должны быть сериализованы. Это уменьшит вероятность непреднамеренного обнародования данных при изменении ваших моделей. «Явное лучше неявного».

Классы-сериализаторы принято выносить в отдельный файл serializers.py.

Инструментарий для тестирования API

В процессе работы вы уже отправляли запросы к серверам — из браузера, если в ответ ожидалась HTML-страница, или из кода посредством библиотеки requests (когда ответ сервера надо было обработать в коде).

Для отправки запросов есть и специальные программы, заточенные под работу с API.

Такие программы можно условно разделить на консольные (такие как curl и httpie), встраиваемые (плагины для браузера или для редактора кода, например, REST Client для VS Code) и графические (Postman).

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

При разработке и тестировании вашего API вам обязательно понадобится один из этих инструментов. Не спешите устанавливать все сразу, выберите приложение, которое вам больше понравится. В дальнейшем курсе примеры запросов и ответов будут показаны в интерфейсе Postman, но решение, в какой из программ работать, остаётся за вами.

Не пожалейте времени и внимательно рассмотрите ответы тех API, к которым будут отправляться тестовые запросы в этом уроке. Там можно увидеть много интересного: структуру разных JSON, принципы вложенности и именования объектов и полей — всё то, о чём был разговор в прошлом уроке.

Тестирование API через httpie

httpie — консольный API-клиент. Для знакомства с ним нет нужды его устанавливать, Попробовать его в работе можно в веб-эмуляторе. Откройте его и для активации нажмите Enter или Return.

В «веб-консоли» появится заранее написанный PUT-запрос к эндпоинту pie.dev/put/; в запросе передаётся заголовок API-Key и параметр hello со значением world.

Нажатием на Enter отправьте запрос к тестовому API — и вы увидите ответ сервера:

PUT /put HTTP/1.1
API-Key: foo
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 18
Content-Type: application/json
Host: pie.dev
User-Agent: HTTPie/2.3.0

{
    "hello": "world"
}

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
CF-Cache-Status: DYNAMIC
CF-RAY: 6430db7dcc26924c-EWR
Connection: keep-alive
Content-Encoding: gzip
Content-Type: application/json
Date: Tue, 20 Apr 2021 19:42:42 GMT
NEL: {"max_age":604800,"report_to":"cf-nel"}
Report-To: {"group":"cf-nel","endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report?s=549OJOMAtbaQ9GN45r0Ct2rFBGJcMTFRCQvUGJZ8KCIm8noJzceAWKylg6S57AlrnpJhERD6GqiKby91%2FbU1ZX%2F0HwwYXxDM"}],"max_age":604800}
Server: cloudflare
Set-Cookie: __cfduid=d5a88aa57823d025fbe244fa2bdef122b1618947762; expires=Thu, 20-May-21 19:42:42 GMT; path=/; domain=.pie.dev; HttpOnly; SameSite=Lax
Transfer-Encoding: chunked
alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400
cf-request-id: 099267829e0000924c7d091000000001

{
    "args": {},
    "data": "{\"hello\": \"world\"}",
    "files": {},
    "form": {},
    "headers": {
        "Accept": "application/json, */*;q=0.5",
        "Accept-Encoding": "gzip",
        "Api-Key": "foo",
        "Cdn-Loop": "cloudflare",
        "Cf-Connecting-Ip": "192.241.133.165",
        "Cf-Ipcountry": "US",
        "Cf-Ray": "6430db7dcc26924c-FRA",
        "Cf-Request-Id": "099267829e0000924c7d091000000001",
        "Cf-Visitor": "{\"scheme\":\"http\"}",
        "Connection": "Keep-Alive",
        "Content-Length": "18",
        "Content-Type": "application/json",
        "Host": "pie.dev",
        "User-Agent": "HTTPie/2.3.0"
    },
    "json": {
        "hello": "world"
    },
    "origin": "192.241.133.165",
    "url": "http://pie.dev/put"
} 

Если этот консольный API-клиент придётся вам по душе — инструкцию по установке вы найдёте там же, на сайте разработчиков.

Тестирование API через расширение для VS Code

Расширение REST Client позволяет прямо из VS Code отправлять HTTP-запросы и в этом же интерфейсе просматривать ответы на них. Установка расширения стандартна: в строке поиска панели "Extensions" нужно ввести название плагина "REST Client"” и нажать кнопку “Install” («Установить»).

Можно потренироваться, отправляя запросы к бесплатному API проекта {JSON} Placeholder. Этот проект имитирует социальную сеть: в нём хранятся посты и комментарии к ним. На главной странице проекта есть примеры запросов, описание всех доступных ресурсов, эндпоинтов и методов.

Запросы в REST Client нужно сохранять в файле с расширением .http. Если вы решите поработать с этим плагином — после установки создайте в VS Code новый файл (например requests.http) и создайте в нём запрос:

# пример GET запроса
GET https://jsonplaceholder.typicode.com/posts/1 

В файле можно описать несколько разных запросов и отдельно выполнить любой из них. Запросы в файле отделяются друг от друга строками, содержащими три символа #.Добавьте в файл ещё один запрос, пусть это будет POST.POST-запросы в REST Client пишутся так:

###

POST https://jsonplaceholder.typicode.com/posts
Content-Type: application/json

{
    "title": "My Title",
    "body": "My text",
    "userId": 1
} 

Для отправки любого запроса нажмите над ним ссылку “SendRequest”. В правой части экрана вы увидите ответ сервера:

Файл с запросами можно сохранить в репозитории, и любой разработчик сможет отправить сохранённые запросы и посмотреть результат.

Тестирование API через Postman

Postman — популярный и удобный API-клиент, он умеет отправлять запросы и показывать ответы, сохраняет историю запросов и данные об аутентификации, позволяет проектировать и тестировать API.

Управлять запросами в Postman можно и через браузерное приложение, но для работы с локальным проектом потребуется скачать и установить программу на компьютер: работать через браузер с локальным IP 127.0.0.1 не получится, он не будет доступен.Скачайте Postman со страницы загрузки проекта и установите его на свою рабочую машину.

Установка Postman

Авторизуйтесь в приложении, это позволит работать в интерфейсе Workspace (системе для создания и сохранения запросов для каждого проекта по отдельности) и даст некоторые другие бонусы, например — хранение настроек и истории запросов в облаке.

Postman Workspace

Postman может сохранять запросы, ответы, токены и другую рабочую информацию; вы в любой момент можете одним кликом отправить заранее настроенный и сохранённый запрос. При работе с несколькими проектами удобно разделять эти данные, хранить данные каждого проекта отдельно.

Workspace — это своего рода окружение проекта, cпособ разделить настройки разных сервисов.

Например, вы тестировали сервис с котиками, установили для него токен аутентификации, сохранили примеры запросов, всё настроили — а потом вам пришлось перейти к тестированию другого проекта, с пёсиками например.

В такой ситуации Workspace в Postman позволит просто переключиться на другое окружение и создать там другие запросы и токены, относящиеся к новому проекту.На стартовой странице приложения выберите закладку “Workspace” и нажмите на “My Workspace” — это первое, предварительно созданное рабочее окружение. Его можно переименовать и настроить в нём запросы для своего проекта.

После нажатия на кнопку “My Workspace” откроется основной интерфейс Postman.

Главный экран делится на две части:

  • слева — список сохранённых запросов и история изменений, у вас их пока нет;
  • справа — рабочая область: тут можно создавать запросы и настраивать их.

Интерфейс может немного отличаться от скриншотов — это зависит от версии программы, но функциональность остаётся та же.

Чтобы создать запрос, кликните по кнопке «+» над рабочей областью.

Окно настройки запроса

Здесь можно указать и отредактировать любые настройки:

  • метод запроса;
  • URL, по которому нужно отправить запрос;
  • параметры запроса;
  • заголовки запроса;
  • тело запроса.

Теперь можно поупражняться.

У GitHub есть отлично документированное API, вот туда и отправьте тестовый GET запрос на получение данных аккаунта praktikum:

Скопировать код https://api.github.com/users/yandex-praktikum 

Если всё сделано как надо — ответ будет таким:

{
    "login": "yandex-praktikum",
    "id": 58176000,
    "node_id": "MDQ6VXNlcjU4MTc2O",
    "avatar_url": "https://avatars.githubusercontent.com/u/58176914?v=4",
    "gravatar_id": "",
    "url": "https://api.github.com/users/yandex-praktikum",
    "html_url": "https://github.com/yandex-praktikum",
    "followers_url": "https://api.github.com/users/yandex-praktikum/followers",
    "following_url": "https://api.github.com/users/yandex-praktikum/following{/other_user}",
    "gists_url": "https://api.github.com/users/yandex-praktikum/gists{/gist_id}",
    "starred_url": "https://api.github.com/users/yandex-praktikum/starred{/owner}{/repo}",
    "subscriptions_url": "https://api.github.com/users/yandex-praktikum/subscriptions",
    "organizations_url": "https://api.github.com/users/yandex-praktikum/orgs",
    "repos_url": "https://api.github.com/users/yandex-praktikum/repos",
    "events_url": "https://api.github.com/users/yandex-praktikum/events{/privacy}",
    "received_events_url": "https://api.github.com/users/yandex-praktikum/received_events",
    "type": "User",
    "site_admin": false,
    "name": null,
    "company": null,
    "blog": "",
    "location": null,
    "email": null,
    "hireable": null,
    "bio": null,
    "twitter_username": null,
    "public_repos": 6,
    "public_gists": 0,
    "followers": 90,
    "following": 0,
    "created_at": "2019-11-25T13:38:59Z",
    "updated_at": "2021-03-24T16:15:56Z"
} 

Данные аккаунтов на Github открыты, получить их может кто угодно. Запросите данные своего аккаунта:

https://api.github.com/users/<ваш-логин-на-гитхабе> 

Можно получить информацию и о конкретном репозитории в аккаунте: надо лишь покопаться в документации и найти нужный метод.

REST API: Проектирование

Проектирование API — важная часть разработки и хорошая инвестиция в успешный результат. Соблюдение принципов проектирования поможет сделать API современным и удобным в работе. Начнём с принципов консистентности и расширяемости.

Консистентность

Консистентность — это согласованность данных друг с другом, их целостность и внутренняя непротиворечивость. Например, данные о каком-то объекте, полученные с одного эндпоинта, не должны отличаться от данных о том же объекте, но полученных с другого эндпойнта.

Другой случай соблюдения принципа консистентности: одинаковые типы данных должны быть описаны одинаково, где бы они ни использовались.В проекте Yatube есть модель Post. Немного упростим эту модель и рассмотрим работу API на её примере.

# Тестовая модель
class Post(models.Model):
    text = models.TextField()
    group = models.ForeignKey(Group, on_delete=models.CASCADE, blank=True, null=True)
    pub_date = models.DateTimeField('Дата публикации', auto_now_add=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE) 

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

«Пусть это будет unix-timestamp», — решил разработчик:

# GET запрос поста с id=10
GET /api/v1/posts/10/

# Ответ API
[[10, "Это текст из моего поста.", 1618567801, 1]] 

Когда формат даты выбран — в дело вступает принцип консистентности, который предполагает, что и все другие запросы должны возвращать дату именно в этом формате.

Пример нарушения консистентности — в следующем листинге: при запросе комментария дата возвращается строкой.

# GET запрос первого комментария к посту с id=10
GET /api/v1/posts/10/comments/1/

# Ответ API c датой в формате строки - консистентность нарушена
[[1, "Это мой первый комментарий.", "2020-03-23T18:02:33.123543Z", 10]] 

Это непорядок, надо переделать.Если же разработчик не забыл о консистентности — ответ API будет таким:

# GET запрос первого комментария к посту с id=10
GET /api/v1/posts/10/comments/1

# Ответ API c датой в формате unix-timestamp
[[1, "Это мой первый комментарий.", 1618565516, 10]] 

Вот теперь разработчик молодец.

Согласованность

Понятие консистентности включает в себя и идею согласованности: добавление в API новой функциональности не должно сломать API.

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

# GET запрос поста с id=10
GET /api/v1/posts/10/

# Ответ API
[[10, "Это текст из моего поста.", 1618567801, 1]] 

Клиенты успешно принимают ответ и ожидают, что элемент списка с индексом 0 — это id объекта, а под индексом 2 хранится время в формате unix-timestamp.

Но в какой-то момент потребовалось расширить ответ и дополнительно возвращать в ответе id группы, в которой был опубликован пост. Разработчик изменяет ответ, добавив в него новый элемент:

# Новый ответ API
[[10, "Это текст из моего поста.", 7, 1618567801, 1]] 

На первый взгляд ничего страшного не произошло, но теперь в элементе с индексом 2 хранится не время, а id группы; в результате все приложения, которые подключены к API, перестанут работать.

Можно предположить, что именно в этот момент в службу поддержки начнут писать и звонить недовольные клиенты: «Ваш API сломался!». А он не сломался — он просто начал работать по-другому. Но клиентам от этого не легче.

Нужно искать выход из сложившейся ситуации. Можно создать новую версию API и применить изменения в ней, оставив существующую версию в прежнем виде. Такая практика встречается повсеместно (а иногда это вообще единственный доступный вариант).

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

Расширяемость

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

Сейчас API возвращает данные в виде упорядоченного списка: [[1, "Это мой первый комментарий.", 1618565516, 10]]. Так иногда делают для повышения производительности, но в нашей ситуации этот вариант оказался непрактичен: он усложняет расширяемость. Здесь лучше отдавать данные в более распространённом для JSON формате, аналогичном словарю, со структурой {"ключ": "значение"}.

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

# Ответ API в формате "ключ": "значение"
[{
    "id": 10,
    "text": "Это текст из моего поста.",
    "pub_date": 1618567801,
    "group_id": 7,
    "author_id": 1
}] 

Уже неплохо. Но лучше бы предусмотреть и следующий уровень расширяемости: что, если потребуется добавить к информации о посте какие-то данные, которых нет в модели Post?

Например, при запросе GET /api/v1/posts/10 возвращаемую информацию о посте с id=10 можно расширить дополнительными данными: это может быть, допустим, набор ссылок на посты, похожие на запрошенный.

Этот случай можно и нужно учесть на этапе проектирования. Лучше сразу предусмотреть возможность добавления в ответ дополнительных (но не являющихся частью модели) данных. Для этого нужно немного изменить структуру ответа.

В нашем примере для добавления списка ссылок к ответу нужно:

  • выделить возвращаемую информацию о посте в JSON-объект post;
  • добавить в возвращаемый JSON объект links, в котором будут перечислены нужные ссылки.

Такой подход позволит добавлять в ответ и другие объекты без опасения сломать парсеры у клиентов.

Итоговый вариант может быть примерно таким:

// Ответ API в формате "ключ": "значение" с ссылками на похожие посты
[{
    "post": {
        "id": 10,
        "text": "Это текст из моего поста.",
        "pub_date": 1618567801,
        "group_id": 7,
        "author_id": 1
    },
    "links": {
        "link1": "/posts/12",
        "link2": "/posts/23",
            ...
    }
}] 

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

Вот это и называется расширяемостью. Тщательное проектирование API даст возможность расширять ответы без опасности поломать что-то уже существующее.

Самая лучшая структура JSON для API

В природе не существует «самой лучшей», эталонной структуры ответа API. Нельзя корректно ответить на вопрос «что лучше — велосипед или чайник?», всё зависит от ситуации; точно так же и для каждого проекта существует своя лучшая архитектура. И одна из задач разработчика — найти и реализовать её.

Для одного проекта лучшей структурой может быть тот плоский список, с которого мы начинали: ответ получается лаконичен, это экономит ресурсы и трафик; для другого проекта даже структура нашего финального JSON не сможет учесть все необходимые варианты и требования.

Отправка чат-бота Telegram на сервер Heroku

При выключении вашего компьютера бот станет недоступен. Хорошо бы переселить его на какой-то компьютер, который никогда не спит.

Можно приобрести мини-компьютер, например популярный Raspberry PI, воткнуть его в розетку, подключить к домашнему интернету и поселить бота внутри него.

Но если у вас дома отключат электричество или интернет, то возникнет проблема.

Есть ещё один вариант — в телефон на базе Android можно установить Termux, Linux-терминал для Android (ведь Android — это одна из ветвей Линукса).

С помощью этого терминала можно запускать питоновские файлы на смартфоне, как на сервере. После этого можно перенести бота на мобильник, запустить его через терминал — и готово, бот крутится у вас в кармане! Мобильный телефон всегда включён, мобильный интернет доступен.

Но и тут есть свои неудобства: нужно поддерживать заряд батареи и положительный баланс на счёте.

Всё это выглядит не очень надёжно: такие решения, конечно, будут работать, но они годятся только для игрушечных проектов. Чтобы обеспечить уверенную работу приложения, нужен постоянно подключённый к сети полноценный масштабируемый компьютер.

Такие компьютеры называют «удалёнными серверами», а размещение проектов на удалённых серверах называют «услугой хостинга» или просто «хостингом». Обычно за услуги хостинга берут деньги, но есть и бесплатные варианты.

Задание: разместите бота на сервисе Heroku

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

  1. Зарегистрируйтесь на Heroku.
  2. После успешной регистрации и подтверждения почты вы окажетесь на странице https://dashboard.heroku.com/apps.
  3. Создайте приложение (кнопка New → Create new app).

Вас попросят придумать название для приложения и выбрать регион. Укажите географически близкий к вам регион: даже в интернете физические расстояния имеют значение.

  1. Теперь привяжите аккаунт на GitHub: зайдите в раздел Deploy, выберите GitHub в разделе Development method и нажмите на кнопку Connect to GitHub.

После подтверждения действия (вас попросят ввести пароль) укажите название репозитория, в котором находится код:

Осталось только нажать на кнопку Deploy Branch: Heroku установит все зависимости и опубликует приложение на сервере.

Имейте в виду: чтобы всё завелось, нужно поместить в репозиторий два служебных файла:

  • requirements.txt со списком зависимостей, чтобы Heroku знал, какие пакеты ему нужно установить;
  • файл Procfile, в котором должна быть указана «точка входа» — файл, который должен быть запущен.

Здесь доступен пример размещения проекта на Heroku, прочтите его, и картина прояснится.

Подробные инструкции есть в документации, прочтите и их.

Теперь нужно передать на сервер переменные окружения. Откройте вкладку Settings и найдите пункт Config Vars. Нажмите Reveal Config Vars и добавьте поочерёдно ключ и значение для каждой переменной: PRAKTIKUM_TOKENTELEGRAM_TOKENTELEGRAM_CHAT_ID.

Чтобы запустить приложение, необходимо перейти во вкладку Resources и активировать переключатель напротив строки worker python homework.py.

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

Если что-то пойдёт не так, то можно почитать логи, для этого нажмите More → View Logs.

Обратите внимание на ограничения бесплатного аккаунта Heroku: между запросами не должно быть более получаса, иначе сервер «уснёт» и перестанет отвечать. Пусть бот опрашивает API домашки раз в 20 минут или около того.