Перетворювачі Bot API
Проміжний обробник — це функція, яка обробляє обʼєкт контексту, тобто вхідні дані.
grammY також надає вам можливість робити протилежне. Перетворювач — це функція, яка обробляє вихідні дані, тобто:
- назву методу API бота, який потрібно викликати,
- обʼєкт вмісту запиту, що відповідає методу.
Замість того, щоб використовувати next
як останній аргумент для виклику наступного проміжного обробника, ви отримуєте prev
як перший аргумент для виклику наступних перетворювачів. Перегляньте сигнатуру типу Transformer
(довідка API grammY), і ви побачите, як вона відповідає цьому. Зауважте, що Payload<M
посилається на обʼєкт вмісту запиту, який має відповідати даному методу, а Api
це тип результату, що повертається викликаним методом.
Останній викликаний перетворювач є вбудованим викликом, який виконує такі дії, як серіалізація JSON певних полів і, врешті-решт, виклик fetch
.
Для перетворювачів не існує еквівалента класу Composer
, оскільки це, мабуть, надмірність, але, якщо він вам потрібен, ви можете написати власний. PR вітається! 😉
Встановлення перетворювача
Перетворювач можна встановити на bot
. Ось приклад для перетворювача, який нічого не робить:
// Перетворювач, який нічого не робить
bot.api.config.use((prev, method, payload, signal) =>
prev(method, payload, signal)
);
// Порівняємо з таким самим марним проміжним обробником
bot.use((ctx, next) => next());
2
3
4
5
6
7
Ось приклад перетворювача, який запобігає всім викликам API:
// Неправильно повертаємо `{ ok: true } as any` замість відповідних типів обʼєктів.
bot.api.config.use((prev, method, payload, signal) => ({ ok: true } as any));
2
Ви також можете встановити перетворювачі на обʼєкті API обʼєкта контексту. Після цього перетворювач буде використовуватися лише тимчасово для запитів API, які виконуються для цього конкретного обʼєкта контексту. Виклики bot
залишаються без змін. Виклики через обʼєкти контексту паралельно запущеного проміжного обробника також не зачіпаються. Як тільки відповідний проміжний обробник завершує роботу, перетворювач буде відкинуто.
bot.on("message", async (ctx) => {
// Встановимо на всі обʼєкти контексту, які обробляють повідомлення.
ctx.api.config.use((prev, method, payload, signal) =>
prev(method, payload, signal)
);
});
2
3
4
5
6
Параметр
signal
завжди слід передавати вprev
. Він дозволяє скасовувати запити і є важливим для роботиbot
..stop
Перетворювачі, встановлені на bot
, будуть попередньо встановлені на кожному обʼєкті ctx
. Отже, виклики до ctx
будуть перетворені як перетворювачами, встановленими на ctx
, так і перетворювачами, встановленими на bot
.
Випадки використання перетворювачів
Перетворювачі настільки ж гнучкі, як і проміжні обробники, і вони мають так само багато різних застосувань.
Наприклад, плагін для інтерактивних меню встановлює перетворювач для перетворення вихідних екземплярів меню на відповідний вміст запиту. Ви також можете використовувати їх для
- реалізації обмеження запитів,
- імітування запитів до API під час тестування,
- додавання повторення запитів,
- багато чого іншого.
Зауважте, однак, що повторний виклик API може мати дивні побічні ефекти: якщо ви викликаєте send
і передаєте екземпляр потоку читання в Input
, то потік буде прочитано при першій спробі запиту. Якщо ви знову викличете prev
, потік може вже бути частково використано, що призведе до пошкодження файлів. Тому надійніше передавати шлях до файлу до Input
, щоб grammY за потреби міг відтворити потік.
Розширювач для API
grammY має розширювач для контексту, за допомогою яких можна налаштувати тип контексту. Сюди входять методи API: як ті, що знаходяться безпосередньо на обʼєкті контексту: ctx
тощо, так і всі методи в ctx
і ctx
. Однак ви не можете змінювати типи bot
та bot
за допомогою розширювача для контексту.
Ось чому grammY підтримує розширювачі для API. Вони вирішують цю проблему:
import { Api, Bot, Context } from "grammy";
import { SomeApiFlavor, SomeContextFlavor, somePlugin } from "some-plugin";
// Розширювач для контексту
type MyContext = Context & SomeContextFlavor;
// Розширювач для API
type MyApi = Api & SomeApiFlavor;
// Використовуємо обидва типи розширювачів
const bot = new Bot<MyContext, MyApi>("");
// Встановлюємо певний плагін
bot.api.config.use(somePlugin());
// Тепер викличемо `bot.api` зі зміненими типами з розширювачем для API.
bot.api.somePluginMethod();
// Також використаємо налаштований тип контексту з розширювачем для контексту.
bot.on("message", (ctx) => ctx.api.somePluginMethod());
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Розширювачі для API працюють точно так само, як і розширювачі для контексту. Існують як додавальні, так і перетворювальні розширювачі для API, а кілька розширювачів для API можна комбінувати так само, як і розширювачі для контексту. Якщо ви не впевнені, як це працює, поверніться до розділу про розширювачі для контексту у посібнику.