Персонализирани страници за грешки в React с GraphQL и граници на грешки

Страхотната страница за грешки на GitHub 500

Ако ви харесва тази статия, моля, подкрепете ме, като проверите Pull Reminders, Slack бот, който изпраща на вашия екип автоматични напомняния за заявки за изтегляне на GitHub.

Едно предизвикателство, с което наскоро се сблъсках, докато работя с GraphQL и React, беше как да се справя с грешките. Като разработчици вероятно сме въвели по подразбиране 500, 404 и 403 страници в сървър-приложения, но да разберем как да направите това с React и GraphQL е сложно.

В тази публикация ще говоря за това как нашият екип подходи към този проблем, за крайното решение, което внедрихме, и интересни уроци от спецификацията на GraphQL.

Заден план

Проектът, върху който работех, беше доста типично CRUD приложение, изградено в React, използвайки GraphQL, Apollo Client и express-graphQL. Искахме да се справим с някои видове грешки - например сървърът да е надолу - чрез показване на стандартна страница за грешки на потребителя.

Първоначалното ни предизвикателство беше да открием най-добрия начин да съобщим грешки на клиента. GraphQL не използва HTTP кодове за състояние като 500, 400 и 403. Вместо това отговорите съдържат масив от грешки със списък на нещата, които се объркаха (прочетете повече за грешките в спецификацията на GraphQL).

Например, как изглежда нашия GraphQL отговор, когато нещо се счупи на сървъра:

Тъй като отговорите на грешки в GraphQL връщат код на състоянието на HTTP 200, единственият начин да се идентифицира видът на грешката беше да се провери масивът от грешки. Това изглеждаше като лош подход, тъй като свойството на съобщението за грешка съдържаше изключението, хвърлено на сървъра. Спецификацията на GraphQL заявява, че стойността на съобщението е предназначена за разработчици, но не уточнява дали стойността трябва да бъде четено от човека съобщение или нещо, предназначено да се обработва програмно:

Всяка грешка трябва да съдържа запис с ключовото съобщение с стриктно описание на грешката, предназначена за разработчика като ръководство за разбиране и коригиране на грешката.

Добавяне на кодове за грешки към графичните отговори

За да разрешим това, към нашите обекти за грешки добавихме стандартизирани кодове за грешки, които могат да бъдат използвани от клиенти за програмно идентифициране на грешки. Това беше вдъхновено от това как REST API на Stripe връща стринг кодове за грешки в допълнение към четими от човека съобщения.

Решихме да започнем три кода за грешка: authentication_error, resource_not_found и server_error.

За да добавим тези към нашите отговори на GraphQL, ние предадохме нашата собствена функция formatError, за да express-graphql, която представя изключенията, хвърлени на сървъра, към стандартните кодове, които се добавят към отговора. Спецификацията GraphQL обикновено обезкуражава добавянето на свойства към обекти с грешка, но го позволява, като влага тези записи в обект с разширения.

Нашите грешки в отговора на GraphQL тогава бяха лесни за класифициране:

Докато ние разработихме собствен начин за добавяне на кодове към отговорите, генерирани от express-graphql, изглежда, че Аполо-сървърът предлага подобно вградено поведение.

Предоставяне на страници за грешки с Реактивни граници на грешки

След като измислихме добър начин за справяне с грешки в нашия сървър, насочихме вниманието си към клиента.

По подразбиране искахме нашето приложение да показва глобална страница за грешки (например страница със съобщение „Опа, нещо се обърка“) всеки път, когато се натъкнахме на server_error, Author_error или Author_not_found. Ние обаче също искахме гъвкавостта да можем да се справим с грешка в конкретен компонент, ако искаме.

Например, ако потребителят въвежда нещо в лентата за търсене и нещо се обърка, ние искахме да покажем съобщение за грешка в контекста, а не да преминем към страница за грешка.

За да постигнем това, първо създадохме компонент, наречен GraphqlErrorHandler, който ще седи между компонентите за заявки и мутации на аполо-клиент и техните деца, за да бъдат представени. Този компонент, проверен за кодове за грешки в отговора, хвърли изключение, ако идентифицира код, за който се интересувахме:

За да използвате GraphqlErrorHandler, ние увихме компонентите за заявки и мутации на аполонов клиент:

След това нашият функционален компонент използва собствения ни компонент за заявки, вместо директен достъп до react-apollo:

Сега, когато нашето приложение React хвърляше изключения, когато сървърът връщаше грешки, ние искахме да обработим тези изключения и да ги съпоставим с подходящото поведение.

Помнете от по-рано, че целта ни беше по подразбиране да покажем страници с глобални грешки (например страница със съобщение „Опа, нещо се обърка“), но все пак имаме гъвкавостта да се справим с грешка локално в който и да е компонент, ако желаем.

Границите на реагиращите грешки осигуряват фантастичен начин за това. Границите на грешките са компоненти React, които могат да хващат грешки в JavaScript навсякъде в дървото на техните компоненти, така че да можете да се справяте с тях с персонализирано поведение.

Създадохме граница за грешка, наречена GraphqlErrorBoundary, която ще улови всички изключения, свързани със сървъра, и ще покаже съответната страница за грешка:

Използваме границата на грешката като обвивка за всички компоненти на нашето приложение:

Границите на грешките могат да се използват по-дълбоко в компонентното дърво, ако искаме да обработваме грешки в компонент, вместо да изобразяваме страница с грешки.

Например, ето какво ще изглежда, ако искаме персонализирано поведение за обработка на грешки в нашия компонент от по-рано:

Увийте-нагоре

GraphQL все още е сравнително нов и обработката на грешки е често срещано предизвикателство, с което изглежда се сблъскват разработчиците. Използвайки стандартизирани кодове за грешки в нашите отговори на GraphQL, можем да съобщаваме грешки на клиентите по полезен и интуитивен начин. В нашите приложения React границите на грешки осигуряват чудесен начин да стандартизираме поведението на грешките в нашето приложение, докато все още имаме гъвкавост, когато имаме нужда от това.