Дыягностыка адказоў Prisma Guard: Модэль дыягностикі на адзеўных этапах
Выучыце, як діаганаваць адзінакія Prisma API, які выйшлі пад час выкарыстоўвання, шляхом прыяснення, у які самэ этап — настройка, выбор вызываючага прыстрою, перакананне данных або адпаведная адпаведнасць — сталася прычына гэтых адзінакоў.
Пачніце адзьявленне з выявлення таго, яка фаза насправды стала прычыной абярэння.
API, створаные на адміністрацыю, могу зламацца ў калькольных разных точках.
Прымечанне: фазы абярэння, описаныя тут, выйшлі з дакументацыі проекту і стабільных сред для відтворэння, а не з статыстыкі шырокага вжывання сярод большой колькасці корыстувачаў.
Маршрутызатор можа адхіліць сябеўскую настройку яшчэ перад тым, как адправіць хоць адну запитанне. Механізм захавання можа адхіліць некоректную структуру як толькі ёна будзе створана. Процес маршрутызацыі запитаў можа зазнаць абярэння яшчэ перад тым, как запрацюе спецыяльны механізм для конкрэтнага варыянта. Адзьявленне правамоўнасці запита можа адхіліць конкрэтны тэкст запита. Операцыя, якая выконваецца ў паводзе певнага дыапазона, можа зазнаць абярэння проста таму, што контекст, на які ёй неабходна, няўжытковы.
Парадоксальна категорыя – гэта калі запит тэхнічна успехваецца, але параметры Prisma, якія ствараюцца, чыста сэмантыка адпаведнай адпаведзі выходзяць за межы таго, што прыпускала логіка прыемлікі.
Кожная з гэтых категорыяў выклікае разныя способы адладжэння і розныя виды тэстаў. Аналіз усей строчкі з адмовай ў дзесяткі разоў менш эфектыва, чым адпаведныя запитанні: калі першы раз з’явілася такая проблема і які слой можа яе зафіксаваць?
Пачніце з карты фаз
Створаны запит Prisma праходзіць чераз калькі розных меж на сваёй дорозе да выканання:
router construction
caller resolution
operation before-hooks
variant before-hooks
guard shape construction
request validation
Prisma argument execution
response transport
Точная парадроза задач, зв’язаных з формамі, можа змяніцца залежна ад таго, чыя форма ў статычным стане чы прыкладзена да контексту выканання, але гэты діаганастычны падзейленне застаецца корыстным ментальным модэлем.
Няўдачы пад час запуску указваюць на проблемы ў апісанні шляхоў. Няўдачы на стадіі вызыву указваюць на логіку выбору варыянтаў. Адказы на кшталт Invalid query і Invalid data указваюць на несувяз межа тэлама запиту і заявленай структурой. Няўдачы палітык указваюць на відсутнасць доверлівага контексту. А калі запит выкананы успешна, але рэзультат неспадзеваны, трэба абсалютна не зважаць на код статусу.
Памятайце, што тэкст адказаў на адказы прыязначаны для конкрэтных версій. Прыклады, якія тут паказаны, створаны на адной фіксаванай комбінацыі: prisma-guard версіі 1.33.0, які работае разам з Zod 4.4.3 і Prisma 6.19.3. Прыклады, якія стосуюцца чытання на адной базе HTTP, выкорыстоўваюць іншую фіксаваную комплектацыю: prisma-generator-express 1.64.4, які работае на Node 22.14.0 проты PostgreSQL 16.6.
Тактычна формуліровка памылкі трэба спрыяць як доказ, прыналежны конкрэтнай камбінацыі версый. Фазу і адказную прычыну трэба спрыяць як модель діагностикавання, якая застанеся корыстной пазнейш.
Да запиту: канфігурацыя не можа стварыць даговор
Канструкцыя рутэра адпаведна за перакранчванне описаў працы перад тым, як адбудзецца што-небудзь іншае.
Забораняецца канфігуруваць аднойчы і shape, і variants для адной операцыі. Карта варіянтов не можа застацца порожняй. Кожны опис варіянта павінен уключаць shape. Забораняецца вжываць зарезерваваныя ключы shape як імены вызываючых элементаў.
Этыя явышчы ў сваёй сутнасі ёсу памылкі часа развяртання. Якщо система ўловіла іх і пры тым продавяжыла работу з напалова канфігуруаваным рутэрам, яна б таямніча стерла межы, якія програма павінна была сабліжваць.
Аперэйш, які не вказвае ні shape, ні variants, — это абсалютна іншая ситуацыя: ён тэхнічна адказны, і ён вызывае Prisma без жадных правілаў абаранення. Чы гэта прийняцьягодна, павінна быць чыстае рашэнне, якое прыймаецца пад час перагляду маршрута, а не выніканне ад случайнасці.
Стварэнне shape мае свою сяброўскую групу умов аббіекцыі. Пустыя комбінаторы, пустыя проекцыі, суперасункі прымусовых прадыкатаў, непачаткаваныя shape-ы, некоректныя структуры upsert і методы bulk без where-shape адхоўваныя з самага пачатку, перш чым данні, якія надае кліент, могуць неабаранена з імі взаінае дзейсцаваць.
Мінімальная репродукцыя ўсё бол корыстна, калі яна выдзеляе стварэнне shape ад слоя транспорту:
const query = guard.query('Plant', 'findMany', {
where: {
name: { contains: true },
},
take: { max: 50, default: 20 },
})
const args = query.parse({
where: {
name: { contains: 'fern' },
},
})
Этот аіслараваны шлях чырпаець добра для тэставання фільтраў чытання, аргументаў сортавання, сторнікацыі і большасці бягаў, выклікваных пад час стварэння структуры дадзеных. Але ён не выкананы проты Prisma, не застаўляе проекцію дадзеных на рэвалюцыі і не паказвае, як фактычна дзейнуюць мутацыі.
Якім бы не быў спосаб развязкі, ён павінен знаходзіцца ў налашчэннях сервера. Жадныя змены ў пакете запыту не можаў вярнуць структуру, якая з самага пачатку ўсталела некоректна.
До обробніка: не удалося выбраць вызывача
Калі вжываюцься іменаваныя структуры дадзеных і ўаріянты, перш чым запыт дасягне створанага обробніка, адбываецца дадатковы этап маршрутацыі.
Калера лічыцца згубленым, калі карта варіянтав не мае элемента default. Калера лічыцца невядомай, калі нішто з яе не падходзіць: няма точнага ключа, няма параметрызаванага шаблона і няма значэння default. Два перакрытых параметрызаваных шаблоны не раз’ясняюцца за дапамою порядку адзычэння; система спрыяе такой ситуацыі як неодназначной і тады выдае адзінаковы рэзультат.
Даныя аідентыфікаціі калера перадаюцца як адзінэ канал, отдельны ад тэла запытку Prisma. Прабавы пасунуць іх у самыя аргументы запытку адхоўваюцца без успеху.
Для контрактаў, назначаных для публікі, выкарыстоўванне заголовка як намеровага селектара калера можа быць разумным выборам у дизайне. Але для прывілейваваных варіянтав выбір должен выконвацца на адной з логікаў аутэнтыкацыі ў функцыі resolveVariant, а не на адной з дадзеных кліента. Выбранне спецыяльнага названня для заголовка не робіць яго значэнне надзеяным.
Адрасаванне паказуеяцца пасля выконання прыемнікаў на рэжыме аперацыі, але да таго часу, калі не выконваюцца прыемнікі, спецыфічныя для варіанта. Гэты порядак падкрэпляе тонкія явышча: логіка аутэнтыфікацыі на рэжыме аперацыі все равно выконваецца, нават калі жаданы варіянт вызывача не падходзіць, тады як прыемнікі, спецыфічныя для вызывача, у такім случае ніколі не запускаюцца.
Правыя рашэнні — гэта не проста «дадзіце стандартны варыянт». Стандартны вызывач мовчкі прыймае вакульныя, порожнія і не падходзячыя значэння вызывача. Дадзіце такі варыянт толькі тады, калі гэтае альтернатыўнае падходжэнне даскладна ўзімліва ў всіх трох сцэнарыях.
Пад час верыфікацыі: запит перакрыў заявленыя межы
Блікі чытання, якія былі перакананы ў гэтым налашчэнні, паказваюць точны шлях аргумента, які іх спрычыніў.
Нез’явленая польна ў where означае, што гэтая польна не ўскладневае структуру фільтра. Нез’явленая польна ў select означае, што запит прагне расширыць проекцію за межы, дазволеныя. Адхілена значэнне skip означае, што прыпінэнне сторанавання ніколі не было увімкнута для гэтай структуры. Канфлікт у take можа означаць або тое, што запрошаная значэнне перасіліла заданы максімум, або тое, што яна была надана ў неправильным скалярным типе.
У гэтым случае важныя ёсць генераваныя памагчыцы для запитаў типу GET, адтолькі ўсе аргументы у формате Prisma не перетвараюцца на однаковы спосаб з моменту стварэння яўных з запитоў. Чысла-фільтры і даты зазвычай перетвараюцца правільна там, дзе гэта падтрымвана, але логічныя значэння і значэнні пагінацыі, прасланыя як строкі, можу не перетварацца належным чынам. Безпечнейшы варыянт — использоваць генераванага кодувальніка для запитоў типу GET або ж вярнуцца да стандартнага JSON через методы чытання, базаваныя на POST.
Натомст, напісанне коду для верыфікацыі выконваецца за структурой, якая є спецыфічной для кожнага методу Prisma. Методы стварэння прыменяюць поле data. Методы апдэйта прыменяюць як where, так і data. Методы упсерта прыменяюць where, create і update. Калі выкалічваецца масовае стварэнне з абаранаванням, як умова прыймаецца тое, што вхідны дадзеныя маюць быць масоўкай.
Масавыя операцыі можу збыцца на двух разных рэвэлях. Якщо у самай форме не ёсць элемента where, то гэта проблема часу будовы. Якщо ж у тэле запита часу выканання тэхнічна ёсць пазначка where, але яна не відпавае ніякой рэальнай умове з боку кліента, тады гэта проблема часу запита.
Памылкі правіл таксама належаць да свайго катагорыі. Відсутнае корэневае значэнне дыямэтру чаргавання або відсутній контэкст для формы, якая залежыць ад контэкста часу выканання, або ўсё гэта свідчыць пра тое, што якаясь частка доверлівага стану проста не ёсць. Установка режыма дзеяння для відсутнега дыямэтру чаргавання ў режым памылкі запобегае тому, каб відсутній контэкст таямна ператворыўся на нефільтруемы запит высшага рэвэля.
Звычка, якую варта выклікати тут, — это зберагчыць точны шлях, дзе ўтворылася проблема. Фраза «прыйшоў код 400 ад захістнага механізма» практычна нічога корыстнага не адказвае. Фраза «функцыя чытання дадзеных прабавілася выконаць include.plants.take пэўным чынам, які перавышае заданы максымальны ліміт» прыводзіць безпосередна да конкрэтнага элемента ў контракце.
Пасля таго, як захістны механізм скасаваў блокаванне: статус 200 все ўсё роўна маскіруе рэальныя рызыкі
Успешнае HTTP-адказванне проста паведамляе, што процес пройшоў да канца. Яно нічога не адказвае пра тое, чыякож была сэрьёзна адразувана запрашаная вам вялічына, чыякож была выканана умова ў той галузі, яку вы прыпускалі, чыякож адказванне викорыстоўвае той формат дадзеных, які вы спачатку чакалі.
Возьмімо абсолютна прымусовая прадыкта вышэйшага рангу: яна заменяе ўсё, што надае кліент, без жадных відчутных знакоў такога дзеяння. Якщо форма фіксуе значэнне isPublished на true, кліент, які надае false, такі ж атрымуе адпаведны ўспэшны адказ, тады як рэальна выконваная запит прытрымліваецца прымусовага значэння true.
Іншыя прымусовыя поля працуюць адваротна — яны проста адхоўляюць значэння, наданыя кліентам, узамест таго, каб таямна іх заменіць. Пакалі прымусаванне можа праявляцца неаднакова залежна ад таго, дзе яно застосаванае, вашы тэсты павінны пераканацца, хто насправды керуе кожным аргументам, узамест таго, каб прыпускаць, што адна інстанцыя force() паслужыць для всіх полей.
Выкананне прымусов стае ўсё сложней у клазу OR. Умова, якая выканана прымусова там, паднімаецца на верхній рэвень і ператвараецца ў обавязковую абмежэння. Такім чынам, форма, якая здаецца выражаючая „альбо умову кліента, альбо умову сервера“, на самай працэ выконваецца як сума умовы кліента і прымусовага предиката, выкарыстоўваючы логіку AND. Якщо вам дасправа патрэбна альтернатыва, якая належыць серверу, вам патрэбна спецыяльная запит, створаная для гэтай меты, або ж вам трэба ўжыць прымусы на роўні правіл базы дадзенаў.
Проекцыя адпаведзі таксама мае сваю супэльную разніцу. Калі кліент не паказвае проекцыю пад час захаванага чытання, прыменяецца стандартная проекцыя формы, але гэта заместаўленне відбываецца тады, калі фактычна выканана дэлегата, а не калі запускаецца guard.query().parse().
Мутацыі не павінны выконвацься за аднаковымі правіламі. Якщо параметр enforceProjection не заданы, кліент, які не вказвае проекцыю для мутацыі, ўзагалі не отрымае клазу select, тое значыць, ў такім случае працюе звычная для Prisma схема без проекцыі.
Застосоўванне правіл у глыбокіх просторах значэнняяў — ўсё той жа момент, калі легка прыпускати большы захоплення, чым на самай працэ. Автаматычны простор значэнняяў перехопляе толькі операцыі верхньага рэвэлю, якія ён прыметна падтрымае. Ён не дасягае да асоціяцый, якія запрашваюцца чераз проекцыю, і не фільтруе іх рэкурсыўна. Да таго ж сам корень простору значэнняяў ніколі не фільтруецца за дапамогою свайго сабеўказчыка, а будь-які необработаны SQL, які вы запускаеце, абходзіць цэлы шар застосоўвання правіл расширэння.
Ніякі з гэтых эфектаў не будзе спостыральны, якщо вы пераканаўцеся толькі ў коде статусу.
Аберыце правильны механізм чытання пры перадпакладанні формату адпаведзі
Створаны слой адаптаваны з трыма разнымі механізмамі для выдачы рэзультатаў чытання: адпаведныя пагінацыійным структурам адпаведзенні, транспорт на базе методу POST і серверныя запусканыя зместы на базе Express.
findManyPaginated вяртае фіксаваную зовнішню структуру:
type PaginatedResult<T> = {
data: T[]
total: number
hasMore: boolean
}
Флаг hasMore є надзеяным спецыяльна для пагінацыі на аднойчынных афсэтах у поўнасці з паазытным значэнням take. Якщо вы викорыстоўваеце пагінацыю на аднойчынных курсарах або негатыўнае значэння take, вы все рава можете атрымаць булевы значэння, але ён больш не мае той самай гаранціі. Значэнне take равнае 0 вяртае нуль рэядоў і флаг продажнення, равны вымышленаму значэнню, тады як загальная колькасць застаецца незменнай.
Абсалютная колькасць вылічваецца па абсалютна іншай логіцы. Розлічэнне разнымі способамі выконваецца са адказаннем прызначанага ліміту. Джэрела прадзеяных падсчытанняў викорыстоўваюцца толькі тады, калі запит не фільтруецца, не захоўваецца і ня є розным. Будзь-які дынамічны фільтр, клазула розлічэння або механізм захавання прымушае перайсці на жывы падсчыт, вылічаны ў момент запиту.
Такой перехід парадкава захоўвае правильнасць, але змінюе як вартасць операцыі, так і мэту, з якой бераеца ця чысла. Семантыку абсалютнай колькасці трэба расследваць як аднае пытанне, незалежная ад семантыкі розрываў рэядоў.
Чытанні на адной заснове POST існуюць для керавання розмерам і кодаваннем пакета дадзеных, а не для расшырэння таго, што можа выразіць язык запитаў:
POST /delivery/paginated
Content-Type: application/json
{"where":{"city":{"equals":"Bangkok"}},"take":20,"skip":0}
Надацеце тэлу як чысты JSON. Адзіныя версіі GET і POST таго ж маршруту павінны выканаць адночыныя правіла захавання. Якщо хук перапісвае тэлу запытку, гэта аднаковасць можа быць наражаная, таму што маршрут GET чытае данні з уже апрацаваных параметраў запыткі, а не з тэлы JSON.
З’явленні сервера зменяюцца ў момент прыбыць дадзенаў, а не таму, якія саме дадзеныя прыбылі. Гэты механізм мае сенс толькі тады, калі кліент фактычна реалізуе обробку з’явленняў пры працэсе, з’явленняў аб успеху, з’явленняў аб неудачы і запасны маршрут.
{"type":"progress","stage":"relations"}
{"type":"field","field":"summary","data":{"total":6}}
{"type":"result","data":{"summary":{"total":6},"deliveries":[]}}
Рулевыя SSE-заданні — это запиты на рэжыме аплікацыі, якія вы самі пішаеце, і ім таксама неабходна явная обработка захісту, як і для будзь-чаго іншага. Функцыя Auto-include паводзіцца толькі з тымі форматамі дадзеных, якія задокументаваны і парадуюць межам дзеяння планавальніка; все, што знаходзится за межамі, обрабоўваецца згодна з налаштаваным механізамом альтернатыўной дзеяння. Крэму, заданні, створаныя пасля хуков, не є гарантаваным спосабам чысткі прайму SSE.
У суме „успешны“ запит на чытанне можа застацца некоректным з кальколька незалежных прычын: ненадзеяны флаг продажэ, неправильна інтэрпретацыя джерела лічбы, специфічная для транспорту дзеяння хуков, або рулевы запит, які ніколі не быў захіщаны.
Направляйце кожны тэст на той шар, які вы можаце фактычна пераканацца
Жадны енд-ту-энд запит не можа адразу пераканаць кожны шар.
Калі вы тэставаеце прабаву дакументаў чы рэштруктуру з прымусовым з’еднаннем, выкарыстоўваеце парсар. Калі пытанне стосуецца праектавання ў час експанатарыі чы аргументаў паступнай мутацыі, выкарыстоўваеце захаванага дэлегата. Калі вы тэставаеце, чы сапраўды адбылася автаматычная ін’екцыя дыапазона, выкарыстоўваеце шлях аперацый расшырэння.
Адскалькаваны прыстрой для захоплення аргументаў дазволяе вам пераглядаць аргументы паступнай мутацыі без з’явлення ў базе дадзенаў, але толькі якщо вы паў’язуеце расшырэнне-захаваннік з дэлегатам, який сапраўды вяртае аргументы, якія ён получыў. Стварэнне адскалькаванага фальшывага об’екта нічога не дазволяе падтвердзіць. Такі прыстрой паведамляе вас, якія аргументы былі выданы, а не якія рэкорды сапраўды будзе вяртаць база дадзенаў.
Для запытанняў пра рэзультаты на адзінцовам лэвеле, прыналежнасць адносаў, паведанне транзакцый, разлічныя сумы чы асоблівасці, прызначаныя для прадаўца, вам патрэбны фікстуры, апараныя на базе базы дадзеных. Заполніце прынеймна двух аб’ектаў-орендароў рядкамі, якія чытна разлічаюцца адзін ад другога, каб у разе выклікання вытэкаў гэта было зрозумела.
Для запытанняў пра генераванне маршрутаў, серыялізацыю, выкананне хуків, эквівалентнасць GET/POST, формат адпаведзей па стораначэнні чы порядак запуску падзеяў SSE, выкорыстоўвайце тэсты на лэвелі HTTP.
Зберагачыце прынеймна адзін тэст кантракта з увёлечаным захаваннем, нават якщо ваша суцэльная пакетная праця браузера запускаецца у режыме, які выключае перакантрольванне захавання. Тэст браузера, які праходзіць у режыме з паслабленымі правіламі, нічога не дазволяе сказаць пра тое, што будзе адхілена ў рэальных умовах, калі шар перакантрольвання быў выключаны для тэста.
Запісуйце кожны тэст регрэсіі на найніжшам слое, які можа падтвердзіць конкрэтную твароўленую ім прызнанне. Болей спецыфічныя тэсты значаюць, што калі пазней ўтворыцца бяда, прычына будзе відносіцца да таго этапу, які ёю керуе, а не будзе прымусваць вас перапрацоўваць увесь шлях запытку з нуля.
Рашайце проблему ў аднам напрамку
Короткая, можна павтарыць последовасць не дазволіць вам здагадвацца пра способы выправлення:
- З’ясавайце, чы гэта бяда падчас запуску, бяда ў момант выканання запытку, чы то успешны адпаведзень, які вас здзівіў.
- Выявіце, який этап несе адпаведальнасць: маршрутызатор, рашэнне запытку, форма, правілы, выканання Prisma чы транспорт.
- Зменшыце процес відтворэння проблемы да адной операцыі, адной формы і аднаго тэлу запытку.
- Аналізуйце аргумент на тым слое, які знаходзіцца найбліжэй да месца, дзе выклікаецца такое паведанне.
API, створаныя такім чынам, стаюць набагато простэйшымі для разумення, калі вы трывожыце ўсі ўжо іх фазы адзіну ад другой. Памылкі ў налашчэннях павінны стаць виднымі ўжо перад тым, як будзе аддаўаныя які-леба запиты. Запыты, якія наражаюцься на памылку, павінны адзначаць точна, якую частку кантракту ўони нарышчылі. А успешны адказ павінен быць перакананы ў спявпаданні з аргументамі, якія ён фактычна выдалаў, і з семантыкай транспорту, якая для ўсьго гэтага задокументавана, а не толькі з кодам статусу.
Спаднёе чытанне
- Усуненне памятай пра Prisma's libssl.so.1.1 Missing Library Error у Alpine Docker — Дазвольце дазнаць, чаму дварчык запитаў Prisma зупіняецца ў адобразах Docker, створаных на базе Alpine, з-за памятай пра відсутную бібліятэку libssl, і як яе назаўсёды усунуць.
- Стварэнне GraphQL API з абезпекай типаў за дапамой Prisma і Nexus у Node.js — Следзіце за семым крокамі, якія паказваюць, як стварыць GraphQL API для Node.js, який адзінавае модэль дадзеных Prisma з типамі та рэзалверамі, створанымі Nexus.