Páginas de error personalizadas en Reaccionar con GraphQL y límites de error

La increíble página de 500 errores de GitHub

Si te gusta este artículo, por favor apóyanme revisando Pull Reminders, un bot de Slack que envía recordatorios automáticos a su equipo para las solicitudes de extracción de GitHub.

Un desafío que encontré recientemente mientras trabajaba con GraphQL y React era cómo manejar los errores. Como desarrolladores, es probable que hayamos implementado previamente 500, 404 y 403 páginas predeterminadas en aplicaciones renderizadas por el servidor, pero descubrir cómo hacer esto con React y GraphQL es complicado.

En esta publicación, hablaré sobre cómo nuestro equipo abordó este problema, la solución final que implementamos y lecciones interesantes de la especificación GraphQL.

Antecedentes

El proyecto en el que estaba trabajando era una aplicación CRUD bastante típica construida en React usando GraphQL, Apollo Client y express-graphQL. Queríamos manejar ciertos tipos de errores, por ejemplo, cuando el servidor está inactivo, mostrando una página de error estándar al usuario.

Nuestro desafío inicial fue encontrar la mejor manera de comunicar los errores al cliente. GraphQL no usa códigos de estado HTTP como 500, 400 y 403. En cambio, las respuestas contienen una matriz de errores con una lista de cosas que salieron mal (lea más sobre los errores en la especificación GraphQL).

Por ejemplo, así es como se veía nuestra respuesta GraphQL cuando algo se rompió en el servidor:

Dado que las respuestas de error de GraphQL devuelven el código de estado HTTP 200, la única forma de identificar el tipo de error era inspeccionar la matriz de errores. Esto parecía un enfoque deficiente porque la propiedad del mensaje de error contenía la excepción lanzada en el servidor. La especificación GraphQL establece que el valor del mensaje está destinado a los desarrolladores, pero no especifica si el valor debe ser un mensaje legible por humanos o algo diseñado para ser manejado mediante programación:

Cada error debe contener una entrada con el mensaje clave con una descripción de cadena del error destinado al desarrollador como guía para comprender y corregir el error.

Agregar códigos de error a las respuestas de GraphQL

Para resolver esto, agregamos códigos de error estandarizados a nuestros objetos de error, que podrían ser utilizados por los clientes para identificar errores mediante programación. Esto se inspiró en cómo la API REST de Stripe devuelve códigos de error de cadena además de mensajes legibles por humanos.

Decidimos iniciar tres códigos de error: autenticación_error, recurso_no_encontrado y servidor_error.

Para agregar esto a nuestras respuestas GraphQL, pasamos nuestra propia función formatError a express-graphql que asigna excepciones lanzadas en el servidor a códigos estándar que se agregan a la respuesta. La especificación GraphQL generalmente desalienta la adición de propiedades a los objetos de error, pero lo permite al anidar esas entradas en un objeto de extensiones.

Nuestros errores de respuesta GraphQL fueron fáciles de clasificar:

Si bien desarrollamos nuestra propia forma de agregar códigos a las respuestas generadas por express-graphql, apollo-server parece ofrecer un comportamiento incorporado similar.

Representación de páginas de error con límites de error de reacción

Una vez que descubrimos una buena forma de manejar los errores en nuestro servidor, dirigimos nuestra atención al cliente.

De manera predeterminada, queríamos que nuestra aplicación mostrara una página de error global (por ejemplo, una página con el mensaje “¡Uy, algo salió mal”) cada vez que encontramos un error de servidor, error de autorización o no encontrado. Sin embargo, también queríamos la flexibilidad para poder manejar un error en un componente específico si quisiéramos.

Por ejemplo, si un usuario estaba escribiendo algo en una barra de búsqueda y algo salía mal, queríamos mostrar un mensaje de error en contexto, en lugar de pasar a una página de error.

Para lograr esto, primero creamos un componente llamado GraphqlErrorHandler que se ubicaría entre los componentes de consulta y mutación de apollo-client y sus hijos para renderizar. Este componente verificó los códigos de error en la respuesta arrojó una excepción si identificaba un código que nos importaba:

Para usar GraphqlErrorHandler, envolvemos los componentes de consulta y mutación de apollo-client:

Nuestro componente de función luego usó nuestro propio componente de consulta en lugar de acceder directamente a react-apollo:

Ahora que nuestra aplicación React arrojaba excepciones cuando el servidor devolvía errores, queríamos manejar estas excepciones y asignarlas al comportamiento apropiado.

Recuerde desde el principio que nuestro objetivo era mostrar páginas de error globales de forma predeterminada (por ejemplo, una página con el mensaje "¡Uy, algo salió mal"), pero aún así tenemos la flexibilidad de manejar un error localmente dentro de cualquier componente si lo deseamos.

Los límites de error de reacción proporcionan una forma fantástica de hacer esto. Los límites de error son componentes React que pueden detectar errores de JavaScript en cualquier parte de su árbol de componentes hijo para que pueda manejarlos con un comportamiento personalizado.

Creamos un límite de error llamado GraphqlErrorBoundary que detectaría cualquier excepción relacionada con el servidor y mostraría la página de error apropiada:

Utilizamos el límite de error como envoltorio para todos los componentes de nuestra aplicación:

Los límites de error se pueden usar más profundamente en el árbol de componentes si queremos manejar los errores en un componente en lugar de representar una página de error.

Por ejemplo, esto es lo que se vería si quisiéramos un comportamiento personalizado de manejo de errores en nuestro componente de antes:

Envolver

GraphQL todavía es relativamente nuevo, y el manejo de errores es un desafío común que los desarrolladores parecen estar enfrentando. Al utilizar códigos de error estandarizados en nuestras respuestas GraphQL, podemos comunicar los errores a los clientes de una manera útil e intuitiva. En nuestras aplicaciones React, los límites de error proporcionan una excelente manera de estandarizar el comportamiento de manejo de errores de nuestra aplicación y, a la vez, tener flexibilidad cuando la necesitamos.