Ինչպե՞ս հաստատել, որ Protobuf հաղորդագրությունը չի պարունակում զրոյական արժեք ունեցող enum դաշտեր: Պարզվում է, որ սա ուղղակիորեն չի աջակցվում Protobuf-ի կողմից: Մենք պետք է նայենք, թե ինչպես է իրականացվում protojson
փաթեթը:
Ավելի ու ավելի շատ ընկերություններ ընդունում են gRPC Protobuf-ով ներքին ծառայությունների միջև հաղորդակցության համար: Այն ունի բարձր կատարողականության առավելություններ, աջակցում է բազմաթիվ ծրագրավորման լեզուներին և աջակցում է Google-ին՝ շրջապատող հիանալի էկոհամակարգով:
Առջևի և արտաքին ծառայությունների հետ հաղորդակցվելու համար Protobuf-ը կարող է փոխակերպվել JSON ձևաչափի: Զննարկիչը հասկանում է միայն JSON ձևաչափը, և մենք չենք կարող ակնկալել, որ այլ ընկերություններ կսպառեն Protobuf-ը անմիջապես մեզանից: (Իհարկե, կարող ես, եթե բավականաչափ մեծ ես:)
Եկեք խոսենք enum-ի և որոշ խնդիրների մասին, որոնք մենք վերջերս բախվել ենք դրա հետ կապված:
Նմուշի կոդը գրված է Go-ում:
Protobuf ոճի ուղեցույցից զրոյական արժեք enum-ը պետք է ունենա UNSPECIFIED
վերջածանց: Դա այն պատճառով է, որ enum-ն իրականացվում է որպես uint32
, իսկ 0
արժեքը համարվում է չճշտված: Այն նման է nil
ին հաղորդագրության կամ դատարկ տողի համար: Protobuf-ը JSON-ով կոդավորելիս nil
հաղորդագրությունը, UNSPECIFIED
enum-ը կամ դատարկ տողը անտեսվում է:
Մենք մինչև մի օր հետևում էինք այդ կոնվենցիային, չէինք անում։
Արտաքին webhook հաղորդագրություններ ուղարկելիս մենք որոշեցինք չօգտագործել 0
-ը որպես UNSPECIFIED
: Պատճառներից մեկն այն է, որ մենք օգտագործում ենք EmitUnpopulated: true
-ը, որպեսզի համոզվենք, որ բոլոր դաշտերը ներառված են JSON-ի ներկայացման մեջ՝ արտաքին կողմերին վեբ-կապիկ հաղորդագրություններ ուղարկելիս: Եվ մենք չենք ցանկանում, որ այդ UNSPECIFIED
արժեքը հայտնվի webhook-ի հաղորդագրություններում, եթե ինչ-որ կերպ մոռանանք enum դաշտը դնել 0-ի: մենք՝ ինժեներներս, դա գիտենք:
Սա շատ դժվարություններ է առաջացնում, ուստի մենք ստիպված եղանք ետ վերադարձնել և 0
արժեքը կրկին դարձնել UNSPECIFIED
: Խնդիրներից մեկն այն է, որ այն ստիպում է ամենուր օգտագործել EmitUnpopulated: true
-ը: Եվ կան վայրեր, որտեղ մենք չենք ցանկանում արտանետել բոլոր չբնակեցված դաշտերը: Ինչպես զանգահարել որոշ երրորդ կողմի API-ներ: Որոշ հաղորդագրություններ խառնվում են UNSPECIFIED
թվերի և ոչ UNSPECIFIED
թվերի միջև; դրանով ճիշտ ձևաչափ ուղարկելու ուղիներ չկան: Օգտագործեք EmitUnpopulated: true
, երրորդ կողմի API-ները չեն հասկանում UNSPECIFIED
; օգտագործեք EmitUnpopulated: false
և որոշ պարտադիր դաշտեր՝ ոչ UNSPECIFIED
թվերով, բաց թողնված են: Իհարկե, դրանք բոլորը կարող են վերափոխվել, բայց սկզբում UNSPECIFIED
-ի օգտագործումը պարտադրելը պետք է ավելի պարզ լինի:
Դե, ինչու՞ պարզապես չհաստատել, որ բոլոր թվային դաշտերը 0-ի վրա չեն դրված webhook հաղորդագրություններում: Դուք կարող եք հարցնել.
Պարզվեց, որ Protobuf 3-ում դա անելու պարզ ուղիներ չկան:
Protobuf 2-ում կա required
տարբերակ՝ կանխելու դաշտի չեղարկումը: Այս տարբերակը հեռացվել է Protobuf 3-ում, քանի որ այն կանխում է վերամշակումը դաշտերը հեռացնելու համար: Եթե մենք մոռանանք թարմացնել բոլոր ծառայությունները, որպեսզի հեռացնենք այդ չօգտագործվող required
դաշտը, հատկապես մի ընկերությունում, որտեղ բազմաթիվ թիմեր են աշխատում, հաղորդագրություններն անգիտակցաբար կհեռացվեն: Ավելի լավ է դա նախապես չպահանջել: (ավելին)
Protobuf 3-ում կար jsonpb.JSONPBMarshaler
ինտերֆեյս: Մենք կարող ենք պարզապես կիրառել այդ ինտերֆեյսը բոլոր թվերի համար, որպեսզի զրոյական արժեք տեսնելիս սխալ վերադարձնեն: Բայց նորից հանվեց։ Որպես արձանագրություն, մենք պետք է հնարավորինս նվազագույնի հասցնենք հարմարեցումը: Հակառակ դեպքում, այդ հարմարեցումը պետք է իրականացվի և պահպանվի բոլոր տարբեր լեզուներով տարբեր թիմերում:
Այսպիսով, ինչպե՞ս վավերացնել զրոյական արժեքը enum դաշտերում:
Մենք պետք է հասնենք արտացոլման փաթեթին. protoreflect.Message
ինտերֆեյսն ունի Range()
մեթոդ՝ յուրաքանչյուր բնակեցված դաշտի վրա կրկնելու համար: Մենք կարող ենք օգտագործել այդ մեթոդը՝ ստուգելու համար, որ զրոյական թվով դաշտեր չկան… Օ՜, սպասիր: Այն կրկնվում է միայն բնակեցված դաշտերի վրա: Այսպիսով, այն չի հայտնաբերի զրոյական արժեքը enum-ում:
Բայց protojson.Marshal()
ֆունկցիան դեռ կարող է բաց թողնել չբնակեցված դաշտեր EmitUnpopulated
տարբերակով: Ինչպե՞ս է դա իրականացնում: Սուզվեք encoding/protojson
-ում, կա կոդի հատված՝ չբնակեցված դաշտերի (աղբյուր) կրկնելու համար: Եկեք գողանանք.
Այն, ինչ անում է վերը նշված կոդը, կրկնվում է լրացուցիչ դաշտերի վրա՝ շրջելով protoreflect.Message.Descriptor().Fields()
-ի վրա: oneof
դաշտերում գտնվող դաշտերը բաց են թողնվել: Չբնակեցված եզակի message
դաշտերը սահմանվում են որպես invalid
(մտածեք որպես null
ստեղծված JSON-ում) նախքան մուտքագրման ֆունկցիա ուղարկելը:
Այդուհանդերձ, գրելու համար մի քիչ ավելի շատ կոդ, ինչպես օրինակ Protobuf-ի բոլոր տարբեր տեսակների վրա կրկնելու շրջագայական մեթոդի ներդրումը՝ հաղորդագրություն, զանգված (կրկնվող), դինամիկ Struct և, իհարկե, enum: Բայց դա լուծելի է. Եվ ես հիմա կարող եմ հանգստանալ:
Շնորհակալություն կարդալու համար:
Want to Connect? Also published at my blog. Follow me on Twitter for more.