Video Summary and Transcription
El CTO de la Guild discute la importancia de mantener sincronizado el esquema de GraphQL y el código de TypeScript. Introducen GraphQL Cogen, una herramienta que genera tipos y código de TypeScript para mejorar la experiencia del desarrollador y la seguridad de tipos. La herramienta también genera hooks de React listos para usar basados en Apollo Client y admite múltiples idiomas e integración con varias herramientas. También discuten la introducción de Type Document Node, que genera un nodo de documento a partir de operaciones de GraphQL. Mencionan las nuevas características de manipulación de cadenas en TypeScript 4.1 y la capacidad de analizar las definiciones de tipos de GraphQL con un lexer. Expresan la necesidad de ayuda de la comunidad para superar las limitaciones en TypeScript al analizar cadenas complejas y multilineales.
1. Introducción a la Integración de GraphQL y TypeScript
Soy Lhothan, el CTO de The Guild, un grupo de desarrolladores de código abierto enfocado en la integración de GraphQL y TypeScript. Mantener el esquema de GraphQL y el código de TypeScript sincronizados es crucial para reducir errores en tiempo de ejecución. GraphQL Cogen es una herramienta flexible que genera tipos y código de TypeScript para mejorar la experiencia del desarrollador y la seguridad de tipos. Vamos a profundizar en los complementos más populares, comenzando con TypeScript, que genera tipos basados en el esquema y las operaciones de GraphQL. También generamos código, como el complemento TypeScript React Apollo.
Hola a todos. Mi nombre es Lhothan. Soy el CTO de un grupo llamado The Guild. Somos un grupo de desarrolladores de código abierto enfocados principalmente en GraphQL y su ecosistema. Hoy estoy aquí para hablar con ustedes sobre GraphQL, TypeScript, la integración de ambos y las herramientas relacionadas. Y también un poco sobre la próxima generación de integración de TypeScript y GraphQL.
Así que empecemos con lo básico. ¿Por qué necesitamos esta integración? Cada lenguaje tiene su propio sistema de tipos. GraphQL tiene su propio sistema de tipos donde se define el esquema de GraphQL. Se llama SDL y luego tenemos TypeScript, que tiene su propio sistema de tipos. Entonces, al escribir el esquema de GraphQL, necesitas mantener sincronizado tu SDL de GraphQL donde defines el esquema real y tu código de TypeScript donde escribes tu implementación real en los resolvers. Puedes hacerlo manualmente y mantenerlo sincronizado manualmente o puedes usar herramientas para eso. Esto es de lo que voy a hablar en este caso. Mantener los dos sistemas de tipos sincronizados es muy importante porque, considera un campo que has eliminado o agregado a tu esquema de GraphQL, debe reflejarse en el código de TypeScript. Por lo tanto, mantener estos dos sincronizados es importante y probablemente reducirá la mayoría de tus errores en tiempo de ejecución relacionados con GraphQL y TypeScript.
Hace unos años tuve problemas con GraphQL y TypeScript, así que comencé con un pequeño proyecto de código abierto llamado GraphQL Cogen. Esto fue hace cuatro años y hoy tenemos una gran comunidad y no solo generamos TypeScript, también generamos C Sharp, Java y mucho más, y generamos más que solo tipos, generamos un código real que puede ayudarte a mejorar tu experiencia de desarrollo y tu seguridad de tipos. Cogen es una herramienta muy flexible, puedes escribir tus propios complementos y configurar la salida para que se ajuste al proceso de generación y agregar tu propio código, así que es bastante genial. Voy a hablar un poco sobre los complementos más populares que tenemos hoy en día que están relacionados con TypeScript. El primero es TypeScript, el que mencioné antes. Este complemento simplemente genera tipos de TypeScript a partir de tu esquema de GraphQL y esto parece muy similar porque los sistemas de tipos son algo similares y nuestro objetivo es generar código en TypeScript que sea lo más similar posible al esquema de GraphQL. Pero el esquema de GraphQL no lo es todo. También tenemos consultas, mutaciones y todo lo que involucra un conjunto de selección, que es una de las características más poderosas de GraphQL, la capacidad de elegir campos y seleccionar exactamente lo que necesitas y no más que eso.
Dado el hecho de que puedes elegir los campos, significa que tus tipos son algo dinámicos y se basan en tu selección de campos. También generamos tipos basados en tus operaciones de GraphQL. Entonces, cuando lo uses en tu código, tendrás una seguridad de tipos completa. Pero esto son solo tipos. También generamos más. Como dije, generamos código. Así que aquí
2. Características del complemento GraphQL Cogen
El complemento genera hooks de React listos para usar basados en Apollo Client y tus operaciones. Compila previamente las operaciones de GraphQL y crea hooks basados en el nombre de la operación. No se necesita especificar manualmente el tipo, ya que los tipos están integrados en los hooks generados. La herramienta también genera una firma completa de Resolvers, utilidades para varios frameworks y admite múltiples lenguajes e integración con varias herramientas. Pruébalo con la demostración en vivo en nuestro sitio web.
es un pequeño ejemplo de otro complemento llamado TypeScript React Apollo. Y este complemento genera hooks de React listos para usar basados en Apollo Client y en tus operaciones. Básicamente, toma tus operaciones de GraphQL, las compila previamente y crea hooks listos para usar basados en el nombre de tu operación. Entonces, cuando lo uses en tu código, todo lo que necesitas hacer es importar el hook, proporcionar tus variables y luego usar los datos. Y la idea es que estamos integrando los tipos en los hooks generados. Por lo tanto, no necesitas especificar manualmente los tipos ni nada por el estilo. Simplemente obtienes autocompletado y validación de tipos para las variables y el tipo de resultado. Así que esto es bastante genial. Como dije, no solo generamos tipos y eso, generamos más.
Hay una firma de Resolvers. Entonces, si eres un desarrollador de backend que escribe tu esquema y implementación de GraphQL, puedes generar una firma completa de Resolvers a partir de tu esquema e integrar tus propios tipos de modelo en esa firma. Generamos algunas utilidades para Apollo Client, pero no solo eso, también para Oracle, solicitud de GraphQL, Vue, Stencil, Angular, lo que sea. Y no solo es JavaScript y TypeScript, también generamos más para otros lenguajes, e integramos básicamente con todas las herramientas disponibles en este tipo de ecosistema. Entonces, puedes usarlo con Webpack y con Gatsby y Next.js. Y recientemente hemos introducido un nuevo complemento para React query, si lo estás usando. Así que pruébalo, tenemos una demostración en vivo muy agradable en nuestro sitio web, puedes probarlo y ver cuál es la salida basada en la entrada que puedes cambiar o agregar. Así que pruébalo.
3. Introducción a Type Document Node
Recientemente, introdujimos un nuevo concepto y complemento en GraphQL Cogen llamado Type Document Node. Genera un nodo de documento a partir de tu operación de GraphQL, incluyendo los tipos del resultado y las variables. Si tu biblioteca de cliente admite el nodo de documento tipado, puedes compilar previamente tus operaciones y obtener seguridad de tipos y autocompletado. Al fusionar los árboles en un solo objeto, la inferencia de TypeScript detecta automáticamente los tipos basados en el documento. El nodo de documento tipo es compatible con GraphQL.js, Apollo Client 3 y Oracle. Se admiten bibliotecas adicionales a través de parches.
Entonces, pasemos al próximo tema. Recientemente, introdujimos un nuevo concepto y un complemento en GraphQL Cogen llamado Type Document Node. Básicamente, lo que estamos haciendo aquí es tomar tu operación de GraphQL y generar un nodo de documento a partir de ella, que es simplemente una representación en forma de objeto de la operación de GraphQL, nada más que eso, pero lo que estamos agregando son los tipos del resultado y los tipos de las variables incorporados en ese objeto.
Entonces, si estás utilizando una biblioteca de cliente que admite un nodo de documento tipado, simplemente puedes compilar previamente tus operaciones de GraphQL en un nodo de documento y usarlo con tu biblioteca y no necesitas especificar nada más. No necesitas agregar tipos, no necesitas establecer explícitamente los genéricos ni nada por el estilo. Simplemente puedes usar los tipos tal como están y obtendrás seguridad de tipo en tus variables y en tu resultado, pero también obtendrás autocompletado basado en el conjunto de selección que elijas y los campos que desees usar. Así que esto es bastante impresionante.
Entonces, si quieres saber cómo funciona. Si no estás utilizando el nodo de documento tipado, lo que estamos generando para ti hoy es un tipo separado para el tipo de resultado de la operación, un tipo separado para las variables de esa operación y un nodo de documento. Como dije, es simplemente una versión compilada de tu consulta de GraphQL. Pero estos tres son separados. Cada uno de ellos se define por separado. Y cuando lo uses, necesitas especificar dos tipos y el objeto del propio documento. Esto podría ser un problema porque usarlo de esa manera significa que si te equivocas en el tipo, no lo detectarás durante el desarrollo y solo lo descubrirás en tiempo de ejecución cuando sea demasiado tarde. Así que estamos pensando en cómo evitar este tipo de tipos establecidos explícitamente. Entonces, lo que hicimos fue tomar ese nodo de documento. Tomamos ese tipo que generamos para el tipo de resultado y el tipo de las variables. Y simplemente fusionamos todos los árboles en un solo objeto. Y la idea es que estamos utilizando la inferencia de TypeScript para detectar automáticamente los tipos basados en el documento que estás pasando. Entonces, si estás utilizando una biblioteca que admite el nodo de documento tipado, todo lo que necesitas hacer es proporcionar tu operación de GraphQL. Obtendrás tipos automáticos y autocompletado basado en esa operación. Así que esto es bastante impresionante. Y aquí, no hay lugar para errores, porque no necesitas especificar tipos manualmente ni nada más. Simplemente úsalo y estará tipado. En este momento, el nodo de documento tipo es compatible directamente desde GraphQL.js. El propio tipo es parte de la implementación de GraphQL.js, por lo que simplemente puedes usarlo desde allí. Y esto gradualmente se convierte en el estándar para este tipo de integración. Apollo Client 3 y Oracle lo adoptaron y ahora lo están utilizando, y si estás utilizando el nodo de documento tipo, todo lo que necesitas hacer es especificarlo y los tipos se inferirán automáticamente. Si no estás utilizando esas bibliotecas, simplemente puedes ir al repositorio del nodo de documento tipo, donde puedes ver una lista de complementos adicionales, bibliotecas adicionales que admitimos. Simplemente puedes usar un parche que proporcionamos y agregará soporte para esas bibliotecas hasta que ellas lo admitan.
4. TypeScript 4.1 Manipulación de Cadenas
En TypeScript 4.1, puedes manipular tipos de cadenas a nivel del compilador. Al definir estructuras específicas y utilizar la inferencia de TypeScript, puedes extraer y manipular subcadenas, validar estructuras y más. Esta potente función te permite convertir cadenas SDL de GraphQL en tipos durante la transpilación del compilador.
Hasta ahora con el nodo de documento tipo, mi próximo tema para hoy es la próxima versión de TypeScript, que es TypeScript 4.1 y la nueva característica impresionante que tiene. En esta versión de TypeScript, podrás usar cadenas y hacer manipulaciones en esas cadenas a nivel del compilador de TypeScript. Esto suena un poco vago, lo sé, pero piensa en tomar tipos de cadena que defines en TypeScript, como ves aquí, y simplemente hacer manipulaciones en el nivel de tu compilador de TypeScript. Aquí, por ejemplo, definimos un tipo con la cadena `world`, y luego tenemos un nuevo tipo con el saludo, y simplemente concatenamos las cadenas, y tenemos un nuevo tipo con esa salida. Así que esto es simple, pero podemos hacer mucho más con ello. Tomemos este ejemplo, por ejemplo. En este ejemplo, definí un nuevo tipo llamado `statement`, y solo tiene una cadena. También definí un nuevo tipo auxiliar llamado `extract name`, y este tipo es un poco sofisticado. Lo que hace es tomar la cadena, cualquier cadena, e intenta extraer una estructura específica de ella. Así que en este caso, lo que estamos haciendo es buscar una estructura que comienza con `hello` y luego algún nombre y luego el resto de la cadena. Aquí estamos utilizando la inferencia de TypeScript para extraer el nombre. Básicamente, estamos diciendo que si esta cadena coincide exactamente con esta estructura, dame ese nombre. De lo contrario, simplemente devuelve `never`, que es nuestra forma de decir que no funcionó. Así que digamos que estoy usando este auxiliar con mi cadena aquí. El tipo extraído, como puedes ver, es `my name`, lo cual es bastante genial. Y esto es todo hecho a nivel del compilador. Así que podemos hacer manipulaciones de cadenas y extraer algún tipo de como subcadenas e incluso detectar estructuras, hacer validaciones. Así que esto es bastante genial, pero esto es una cadena simple. Podemos hacer aún más. Tomemos este ejemplo. En este ejemplo, como puedes ver, tomé la misma cadena, pero agregué más lógica a ese auxiliar. Ahora, en lugar de buscar una estructura específica, `extract name` busca un flujo más dinámico. Así que estamos utilizando la inferencia para extraer el saludo y luego esperamos un espacio y luego el nombre y luego una coma y luego un espacio y luego la pregunta. En lugar de simplemente devolver lo que encontramos, podemos devolver un tipo, un nuevo tipo de script que contiene esto. Por ejemplo, en esta cadena específica vamos a obtener una versión dividida de mi cadena. Así que aquí podemos ver que tengo un nombre que es `my name` y un saludo que es el saludo real y la pregunta, y este es como un tipo de script que podemos usar. Como dije, todo esto sucede a nivel del compilador y podemos tomar cualquier cadena y aplicar cualquier conjunto de reglas. Así que cualquier cadena que siga un estándar o una estructura específica que esté bien definida puede ser colocada aquí y podemos escribir la regla para extraer lo que hay dentro. Esto es asombroso porque hasta ahora lo que estamos haciendo con TypeScript y GraphQL es tomar el GraphQL, convertirlo en AST, y luego tomamos este AST y generamos código y este código se carga más tarde. Pero si podemos tomar el SDL de GraphQL como una cadena y simplemente convertirlo tal cual en un tipo en tiempo real durante el compilador
5. Análisis de las Definiciones de Tipo de GraphQL con Lexer
Puedes tomar cualquier cadena de GraphQL y crear los tipos que representa sobre la marcha. Escribí un lexer básico de GraphQL para descomponer la cadena en pequeñas piezas y analizarla en el nodo del documento. Al comprender los vínculos entre las piezas, podemos crear tipos sobre la marcha a nivel del compilador. Reimplementé el lexer de GraphQL JS en ayudantes de TypeScript para analizar las definiciones de tipo y validar el lenguaje.
La transpilación del código. Esto es asombroso porque puedes tomar cualquier cadena de GraphQL y crear los tipos que representa sobre la marcha. Así que me tomé un tiempo y escribí un lexer muy básico de GraphQL. Como dije, GraphQL es estructurado. Es un lenguaje estructurado. Tenemos este sistema de tipos y tenemos la estructura exacta que define el lenguaje y los componentes que contiene. Está construido como piezas, como pequeñas piezas que se vinculan entre sí. Este tipo de representación se llama lexer. Básicamente, lo que sucede cuando llamas a GraphQL.parse en una cadena es que GraphQL toma la cadena, la descompone en muchas piezas pequeñas y luego toma esas piezas y las analiza en el nodo del documento real y realiza validaciones en ella. Si tomamos, por ejemplo, esta consulta simple, esta definición de tipo en GraphQL, intentemos descomponerla en piezas. Si intentamos entender cuáles son las piezas reales aquí. Tenemos un tipo, la palabra clave tipo, y luego otra palabra, y luego tenemos una llave aquí, y luego tenemos otra... todas estas están bien definidas en GraphQL, llamémoslo diccionario porque esto define cómo está estructurada cada oración en el lenguaje de GraphQL. Entonces, en nuestro caso, así es como se vería, tenemos cómo GraphQL lo descompondría en piezas. Pensando en esta nueva característica en TypeScript y GraphQL, básicamente podemos tomar este tipo de cadena y, sobre la marcha, convertirlo en la representación del tipo. Así que si podemos descomponerlo en piezas, como cada pieza por separado y entender los vínculos entre ellas, eventualmente podemos llegar a un punto en el que podemos tomar una cadena que contiene una definición de GraphQL, ya sea un tipo o una operación, y crear tipos sobre la marcha a nivel del compilador.
Así que hice un pequeño ejemplo de cómo funciona realmente. Lo que hice fue tomar la implementación del lexer original de GraphQL JS e intentar reimplementarlo en ayudantes de TypeScript. La idea detrás de esto es poder definir un lexer de GraphQL que sepa cómo analizar la definición de tipo en tiempo de ejecución y hacer esta validación del lenguaje real. Entonces, lo que sucede aquí es que tomé esta cadena que define una definición de tipo de GraphQL y creé un ayudante de TypeScript llamado parse-graphql-lexer. Y básicamente, lo que hace es buscar caracteres específicos a nivel de cadena y trata de descomponerlo en piezas. Cada pieza simplemente apunta a la siguiente. Así es como funciona el lexer original de GraphQL. Solo estaba tratando de reimplementarlo con el sistema de tipos. Como puedes ver aquí, solo estoy buscando tokens específicos que son conocidos para nosotros y son válidos en el lenguaje de GraphQL. Y lo que estoy haciendo aquí es tratar de extraer cada uno y luego pasar al siguiente. Así que en este caso, comenzamos con el inicio de la cadena y luego aquí, como puedes ver en el resultado, tenemos un nombre. Esta palabra tipo es solo un nombre para la parte del lexer porque aún no se ha analizado. Entonces, lo que estamos haciendo es simplemente nombrarlo. Y luego paso al siguiente, y como puedes ver aquí, comenzamos con el nombre, nombre y luego llave, y esto es bastante como una definición de tipo muy larga porque nuestro objetivo es poder analizar eso en una estructura que luego se pueda utilizar. Así que esto es solo una prueba de concepto. Y la idea aquí era tomar la cadena muy básica y analizarla en piezas que se entiendan.
6. Análisis de Cadenas GraphQL y Búsqueda de Ayuda de la Comunidad
Podemos convertir cadenas gráficas en tipos sobre la marcha, analizar esquemas y operaciones gráficas de forma dinámica y crear firmas de resolutores. Sin embargo, existen limitaciones en TypeScript para analizar cadenas complejas y de varias líneas. Estamos buscando activamente la ayuda de la comunidad para superar estas limitaciones y mejorar el ecosistema de TypeScript y GraphQL.
Este es solo un ejemplo básico de cómo podemos tomar la cadena gráfica y convertirla en un tipo sobre la marcha. Pero en realidad, hay más. Si podemos entender la estructura de una cadena gráfica, podemos analizar esquemas gráficos sobre la marcha. Podemos entender operaciones gráficas sobre la marcha. Y básicamente, tomar cadenas gráficas y hacerlas disponibles para su uso dentro del lenguaje TypeScript. Entonces, si podemos entender la estructura completa de una cadena, incluso podemos tener una firma de resolutor que se tipa sobre la marcha. Y mucho más en realidad. En este momento, esto es solo una prueba de concepto como dije. Nuestro objetivo es tener más que eso. Pero necesitamos la ayuda de la comunidad. En este momento, hay algunas limitaciones a nivel de TypeScript. No podemos analizar cadenas muy complicadas y no podemos analizar y manejar cadenas de varias líneas que tienen espacios en blanco. Así que estamos tratando de encontrar formas de resolver todo eso y mejorar el ecosistema de TypeScript y GraphQL. Mucho mejor. Entonces, si tienes ideas y esto es algo que te interesa, no dudes en contactarnos y tal vez podamos trabajar juntos. Eso es todo por mi parte. Espero que esta charla haya sido interesante para ti. Si tienes alguna pregunta, no dudes en contactarme o a cualquiera del gremio en el canal de Discord. Eso es todo.
Comments