Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bug] vk.api отправляет параметры, равные undefined #321

Closed
zardoy opened this issue Aug 27, 2020 · 18 comments
Closed
Labels
package: vk-io Issues related to vk-io

Comments

@zardoy
Copy link

zardoy commented Aug 27, 2020

Привет!
Если коротко, то вызов любого API с параметром, у которого явно указано значение undefined приводит к тому, что он передается ВК. Ниже привел пример.

What did you do?

await ctx.send("it'll fail", {
    keyboard: undefined
});

ctx – контекст события message_new

Снимок экрана 2020-08-28 в 00 53 43

What did you expect to happen?

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

What was the actual result?

VK-IO переводит undefined в строку и отдает это серверу.

Versions

package version
vk-io 4.0.1
node 12.17.0
TypeScript 4.0.2
yarn 1.22.4
@zardoy zardoy added the package: vk-io Issues related to vk-io label Aug 27, 2020
@mulfyx
Copy link

mulfyx commented Aug 28, 2020

Нет, постой, это не так работает немножко. Тебе объяснить?

@zardoy
Copy link
Author

zardoy commented Aug 28, 2020

Ну давай, что немножко не так?

@mulfyx
Copy link

mulfyx commented Aug 28, 2020

То, что параметры отправляются с помощью URLSearchParams

const params = {
   message: 'hello',
   keyboard: undefined
};

console.log(new URLSearchParams(params));
// Выведет: URLSearchParams { 'message' => 'hello', 'keyboard' => 'undefined' }

@zardoy zardoy mentioned this issue Aug 28, 2020
@zardoy
Copy link
Author

zardoy commented Aug 28, 2020

@isinkin Да, но я в PR уже написал, что это именно баг, тк TypeScript вообще без разницы параметр не указан или указан со значением undefined, а вот в runtime это уже приводит к ошибки API. Это прям подводный камень какой-то.

@tuogeniy
Copy link

@zardoy почему это баг?

const obj = {
  key: undefined,
}

const properties = Object.getOwnPropertyNames(obj)

console.log(properties)

Свойство объявлено, его тип - undefined и при его преобразовании в строку получается строка 'undefined'.
То что у ts что-то там не так работает уже относится к ts, рантайм у нас на v8, как правило, и он поддерживает только javascript.

@zardoy
Copy link
Author

zardoy commented Aug 28, 2020

const obj = {
  key: undefined,
}

const properties = Object.getOwnPropertyNames(obj)

console.log(properties)

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

vk.api.messages.send({
    message: "undefined" // - так ок
});

Возможно ты прав, что это не баг, а просто подводный камень из-за того, что ts не выкидывает ошибку компиляции при явном указании undefined. Однако моё предложение в PR заключается в том, что бы поведение когда мы параметр опускаем полностью и указываем undefined было одинаковым, тк не всегда

@zardoy zardoy closed this as completed Aug 28, 2020
@zardoy zardoy reopened this Aug 28, 2020
@zardoy
Copy link
Author

zardoy commented Aug 28, 2020

Сори, что закрыл, сейчас дополню.

@tuogeniy
Copy link

@zardoy я понимаю о чем ты.

Наверняка ты пишешь что-то вроде

let someVariable;

const query = {
  key: someVariable,
}

send(query)

Я считаю эта проблема на стороне пользователя, писать нужно по-другому, а этим pr-ом ты ломаешь обратную совместимость.

@zardoy
Copy link
Author

zardoy commented Aug 28, 2020

Я считаю эта проблема на стороне пользователя, писать нужно по-другому, а этим pr-ом ты ломаешь обратную совместимость.

Согласен.

Просто вот смотри где собака зарыта (более наглядный пример):

  • я не мог так прописать

Снимок экрана 2020-08-28 в 13 39 24

  • я вот так уже могу

Снимок экрана 2020-08-28 в 13 39 59

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

@tuogeniy
Copy link

@zardoy так ты ничего не пиши если не хочешь передавать этот параметр, будет работать так как ты хочешь

vk.api.messages.send()

@negezor
Copy link
Owner

negezor commented Aug 28, 2020

Тут скорее несовпадение поведений, при JSON.stringify() будет упущен undefined. В то время когда URLSearchParams приводит всё к строке. Это не будет ломанием обратной совместимости, так как проверяется именно undefined, а не "undefined".

Но теперь мы потеряем интересные сообщения в чате в виде undefined :)

@tuogeniy
Copy link

tuogeniy commented Aug 28, 2020

@negezor про такие сообщения я и имел ввиду, не исключено что кто-то использует тип undefined когда хочет напечатать такой текст)

upd: ну, а вместо undefined будет вылетать exception в некоторых случаях, например когда сообщение пустое.

@mulfyx
Copy link

mulfyx commented Aug 28, 2020

А зачем вы вообще указываете в параметрах undefined?

@zardoy
Copy link
Author

zardoy commented Aug 28, 2020

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

await ctx.send("Hey` there!", {
    keyboard: await getKeyboardToSend() //undefined | KeyboardBuilder - соответствие типов, но ошибка ругается API
});

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

@tuogeniy
Copy link

tuogeniy commented Aug 28, 2020

То что URLSearchParams собирает undefined наверное более гибко и правильно, но менее удобно.

Я плохо знаю vkapi и сурсы этой либы и не могу сказать есть ли проблема, но если проблема разных поведений в одной библиотеке действительно есть, то это надо решать.

Полагаю, что можно передать напрямую body запроса и оно преобразуется в JSON с помощью JSON.stringify, который усекает undefined в отличии от URLSearchParams, это путает пользователей.

@zardoy
Copy link
Author

zardoy commented Aug 28, 2020

То что URLSearchParams собирает undefined наверное более гибко и правильно, но менее удобно.

@talentumtuum не совсем согласен, могу даже пример из другой весьма крупной либы привести.
Есть такая библиотека prisma (через неё можно делать запросы к бд). И вот один из их примеров:

const hisNotes = await prisma.userNote.findMany({
    where: {
        userName: "Dmitriy" // вернет записки только дмитрия
    }
});
const allNotes = await prisma.userNote.findMany({
    where: {
        userName: undefined // не вернет записки пользователя "undefined"
    }
});
// это равносильно
allNotes = await prisma.userNote.findMany({ });

@zardoy
Copy link
Author

zardoy commented Aug 28, 2020

upd: ну, а вместо undefined будет вылетать exception в некоторых случаях, например когда сообщение пустое.

согласен, только вот представь если тебе бот на любую команду будет спамить "undefined". Лучше уж исключение чем silent бессмыслица xd

upd: может хотя бы в логах тогда увидят, да пофиксят

@negezor
Copy link
Owner

negezor commented Aug 29, 2020

Всё же я думаю ошибка лучше, чем проблемный пост. В таких инструментах как Sentry сложно отследить то что не является ошибкой. Мажор 4 версии был нацелен на улучшенное взамодействие с библиотекой и явный undefined не является им.

Это так же исправляет неочевидное поведение между URLSearamParams и JSON.stringify(), исправлено в 1026d33, опубликовано в 4.0.2

@negezor negezor closed this as completed Aug 29, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package: vk-io Issues related to vk-io
Projects
None yet
Development

No branches or pull requests

4 participants