Кто-нибудь может пояснить, как лучше конвертировать мессагу протобафа в JavaScript?
Вот допустим пришло мне сообщение со множеством разных параметров.
export class AnyResponse extends jspb.Message {
getView(): View | undefined;
setView(value?: View): OperationResponse;
hasView(): boolean;
clearView(): OperationResponse;
getAnyParam(): string;
setAnyParam(value: string): OperationResponse;
........
И допустим, где-то в глубине этой кучи данных есть значение value, которое тоже надо получить.
response.getSome()?.getItems()?.getValue()?.toObject() даст нам значение вот в таком виде
"value": {
"fieldsMap": [
[
"id",
{
"nullValue": 0,
"numberValue": 1,
"stringValue": "",
"boolValue": false
}
],
[
"anyNname",
{
"nullValue": 0,
"numberValue": 0,
"stringValue": "Здесь строка",
"boolValue": false
}
],
Это не то, что мне нужно, мне было бы гораздо удобнее получить нормальный объект.
Если я применю response.getSome()?.getItems()?.getValue()?.toJavaScript(), то получится то, что нужно.
"value": {
"id": 1,
"name": "Здесь строка",
.......
}
Но мне необходимо конвертнуть в нормальный объект со значениями весь AnyResponse, который не имеет метода toJavaScript, а он сам и его дети вниз по цепочке являются наследниками jspb.Message и соответственно, имеют только toObject. А value уже google_protobuf_struct_pb.Struct и он может быть обработан через toJavaScript. Вообще-то там массив, и .getValue() нужно еще и циклом перебрать, например. Я пытаюсь упростить код и опустить ненужную информацию, чтобы проблема наглядно сохранилаь.
Апи было спроетировано давно и под json, значения затем сохраняются в стору и класть туда целый объект AnyResponse (jspb.Message) не имеет смысла. Мне очень нужно получить весь объект AnyResponse как простой JavaScript-объект с данными, например через AnyResponse.toObject(), но чтобы там глубоко в value был не fieldsMap, а обычный объект.
Ну вот как можно поступить. Можно
const rowResponse = response.toObject();
const itemsList = response.getSome()?.getItems()?.getValue()?.map(
value => ({
...value.toObject(),
value: value.getValue()?.toJavaScript(),
}),
);
const items = {
...rowResponse.view.items,
itemsList: itemsList,
};
rowResponse.view.items = items;
return rowResponse;
Но это же маразм, должен быть более простой способ. Я здесь примерно идею показал, на самом деле объект больше и хореография слонее. Плюс приходится изворачиваться с типизацией через Omit, потому что как только items изменился, мы уже не можем типизировать респонс через AnyResponse.AsObject
Должен же быть более простой и красивый способ, нежели это.
Но в голову приходит лишь какой-то треш типа переопределения какого-нибудь метода протобафа. Ведь для Items для нас toObject, возвращающий fieldsMap, абсолютно бесполезен. Однако, переопределять именно Items.toObject бессмысленно. Однако, он представлет из себя стену из вызывов
proto.quark.View.Items.toObject = function (includeInstance, msg) {
var f, obj = {
anyNameList: jspb.Message.toObjectList(msg.getAnyNameList(),
proto.quark.Field.toObject, includeInstance),
anyTwoNameList: jspb.Message.toObjectList(msg.getAnyTwoNameList(),
......
};
if (includeInstance) {
obj.$jspbMessageInstance = msg;
}
return obj;
};
Т.е. обратите внимание, не anyValueList: msg.getAnyValueList().toObjectList, а именно jspb.Message.toObjectList(msg.getAnyNameList(), т.е. везде один общий jspb.Message.toObjectList, нельзя адресно переопределить метод конкретно для anyValueList. В принципе, получится не большая разница между этим и тем, что я предлагал выше. Вы таки будете смеяться, но я попробовал. И за исключением того, что я добавил операций в код, который дергается раз 60 на странице, и все-еще страшный костыль, кода стало гораздо меньше и вообще удобнее.
jspb.Message.toObjectList = function (a, b, c) {
const rowResult = jspbMessageToObjectListProto.call(this, a, b, c);
// const svgs = a.findIndex(v=>v && v.getType && v.getType() === 'svg');
const svgIndex = rowResult.findIndex(v=>v.type === 'svg');
if(svgIndex >= 0) {
rowResult[svgIndex].value = a[svgIndex].getValue()?.toJavaScript();
}
return rowResult;
}
Но если все-таки оставить этот дурдом, то ну не могло же такого быть, чтобы не было нормальной штатной возможности получить нормальный объект JavaScript? Что я делаю не так?
Самым очевидным вариантов будет взять все и переписать, чтобы у нас все-таки не было такого божественного jspb.Message, но помимо того, что это просто дохрена придется переписывать, стора как бы тут сильно мешает.
Зы как люди упарываются, чтобы просто получить json
https://github.com/grpc/grpc-web/issues/315
И это продвинутый фреймворк для общения с сервером от гугл?