TypeScript hace que JavaScript sea más seguro al agregar definiciones de tipos estáticos. Las definiciones estáticas son maravillosas; evitan que los desarrolladores cometan errores triviales asegurando que cada asignación e invocación se realice correctamente. Una variable de tipo string no puede recibir un número y una función que espera tres argumentos no puede ser llamada con solo dos. Sin embargo, estas definiciones solo existen en tiempo de compilación; el código que se ejecuta finalmente es simplemente JavaScript. Pero, ¿qué sucede con la respuesta de una solicitud a una API? En esta charla, Ethan Arrowood, Ingeniero de Software 2 en Microsoft, cubrirá diversas soluciones para tipar de forma segura datos dinámicos en aplicaciones TypeScript. Esta charla presenta tecnologías populares como Fastify, JSON Schema, Node.js y más!
Manejo seguro de datos dinámicos con TypeScript
Video Summary and Transcription
Esta charla discute el manejo seguro de datos dinámicos con TypeScript utilizando JSON Schema y TypeBox. Fastify, un framework web, permite a los desarrolladores validar datos entrantes utilizando JSON schema, brindando seguridad de tipos y manejo de errores. TypeBox es una poderosa biblioteca que permite a los desarrolladores definir esquemas JSON y derivar tipos estáticos en TypeScript. La combinación de JSON schema, TypeBox y Fastify proporciona herramientas poderosas para la seguridad de tipos y validación de datos dinámicos.
1. Introducción al manejo de datos dinámicos
Hola a todos. Hoy les hablaré sobre el manejo seguro de datos dinámicos con TypeScript. Como desarrolladores de software, utilizamos datos de diversas formas, como rutas de API, formularios, cargas de autenticación y comunicación entre sistemas grandes. Veamos un ejemplo de un objeto JSON que representa a una persona. JSON es una forma detallada de representar datos y se utiliza ampliamente en las API. Ahora, exploremos una ruta de Fastify y los desafíos de manejar cuerpos de solicitud desconocidos.
Hola a todos. Mi nombre es Ethan Erewood. Soy un ingeniero de software en Microsoft y hoy les hablaré sobre el manejo seguro de data dinámicos con TypeScript.
Entonces, el manejo de data. ¿Qué es data? Como desarrolladores de software, lo utilizamos de muchas formas diferentes. Algunos ejemplos de cómo lo uso son en las rutas de API al construir un servicio backend, al lidiar con forms en el frontend y también en las cargas de authentication y todo lo relacionado con la autenticación en una aplicación de pila completa. Y esta es solo una lista corta. Puedes imaginar lo extenso que puede ser cuando comienzas a lidiar con bases de datos o ciencia de data y simplemente cualquier tipo de comunicación entre sistemas grandes. Así que echemos un vistazo a un ejemplo de un registro de data. En este caso, estoy usando un objeto JSON. Tenemos un montón de claves aquí. ID, nombre, empleado, compañía, edad y proyectos. Estamos representando a una persona. Tal vez este sea un directorio de empleados o tal vez sea un directorio de usuarios para un sitio como LinkedIn donde queremos obtener su nombre, saber si están empleados o no, que es un valor booleano. Queremos saber para qué empresa trabajan. Queremos saber cuántos años tienen. Y también podríamos querer listar sus proyectos. Y como muchos saben, JSON es una forma muy detallada de representar data. Tiene muchas primitivas excelentes que se basan en JavaScript, y puede ser bastante extenso. De hecho, las API completas se basan únicamente en proyectos JSON a través del formato de esquema abierto.
Hablando de API de backend, echemos un vistazo a una ruta de Fastify. En este caso, estamos definiendo una ruta post. La ruta es agregar usuario, y el controlador de solicitud aquí tiene dos argumentos, solicitud y respuesta, y estamos desestructurando el cuerpo de ese objeto de solicitud. ¿Alguien sabe qué tipo de cuerpo podría ser? ¿Es un registro, un objeto, es de cualquier tipo? Pregunta trampa. Es desconocido. La propiedad del cuerpo de ese objeto de solicitud, echando un vistazo nuevamente al código, la ruta de Fastify no tiene idea de qué es porque en el contexto de Fastify como marco de trabajo, no estamos seguros de lo que el desarrollador pretende que se envíe a través de su solicitud. Y no hay forma de que Fastify lo sepa cuando se está escribiendo el código o incluso cuando se está compilando. Bueno, tal vez no cuando se está compilando. Llegaremos a eso más adelante.
2. Manejo de cuerpos de solicitud desconocidos con JSON Schema
Al observar el objeto JSON anterior o tomar una parte del ID y el nombre, hay claves de cadena y valores de cadena. TypeScript lanzará un error. El objeto es de tipo desconocido. Entonces, hay algunos patrones que podemos usar. Puedes usar una conversión de tipo básica donde podemos decir body.name como string. Pero en ese caso, no hay verificación. Ahí es donde quiero presentar JSON Schema. JSON Schema es una API súper poderosa que te permite definir un objeto JSON con más JSON. JSON Schema utiliza una especificación para permitir que un desarrollador defina la estructura de un objeto JSON, especificando el tipo, listando las propiedades, indicando qué propiedades son requeridas o no, listando si hay propiedades adicionales o no, e incluso pudiendo definir tipos más complejos. JSON Schema, y esto solo raspa la superficie de JSON Schema. Puedes usar expresiones regulares, referencias y operaciones lógicas como todas, alguna o ninguna, y es muy poderoso cuando aprovechas JSON Schema para definir tus objetos JSON.
3. Type Safety with JSON Schema and TypeBox
Le das eso a un validador y le dices que se asegure de que mi objeto JSON sea realmente lo que estoy diciendo que debería ser a través del esquema. Lanza un error o dame alguna salida especial si no lo es. Entonces, con eso, tenemos nuestro objeto JSON, esa carga anterior en una mano. Ahora sabemos que podemos definir un esquema para él en la otra mano. Así que déjame presentarte a TypeBox. TypeBox es una biblioteca fantástica que te permite no solo definir esquemas JSON utilizando una API similar a un lenguaje fluido, sino también derivar un tipo estático de ese esquema JSON en tu código TypeScript. Y así, en un ejemplo más complejo, redefinamos nuestro esquema de cuerpo usando TypeBox. Y luego, en el último bloque de este código, Fastify.post, puedes ver que ahora estamos usando un parámetro genérico. Es un objeto, un nombre, me gusta llamarlos parámetros genéricos de nombre. Y hemos asignado ese tipo de esquema de cuerpo T al cuerpo de ese parámetro genérico. El sistema de tipos de Fastify transmitirá ese tipo de esquema de cuerpo T a través de la propiedad de cuerpo del objeto de solicitud. Y eso es genial. Ahora hemos tipado la propiedad de cuerpo del objeto de solicitud.
Aquí tienes un objeto JSON. Le das eso a un validador y le dices que se asegure de que mi objeto JSON sea realmente lo que estoy diciendo que debería ser a través del esquema. Lanza un error o dame alguna salida especial si no lo es. Entonces, con eso, tenemos nuestro objeto JSON, esa carga anterior en una mano. Ahora sabemos que podemos definir un esquema para él en la otra mano. Así que volviendo a la aplicación Fastify y esa ruta, ¿podemos proporcionar alguna seguridad de tipo todavía? No realmente. Todo lo que podemos hacer es validar que el cuerpo entrante sea lo que queremos que sea utilizando JSON Schema. Pero vamos, estamos en 2021. Hay cosas bastante geniales que podemos hacer.
Así que déjame presentarte a TypeBox. TypeBox es una biblioteca fantástica que te permite no solo definir esquemas JSON utilizando una API similar a un lenguaje fluido, sino también derivar un tipo estático de ese esquema JSON en tu código TypeScript. Entonces, dado este ejemplo muy básico, puedes ver en la segunda línea, constante T igual a type.string. Eso va a devolver type.string, un objeto con una propiedad, type, que está establecida como string. Este es un objeto de esquema JSON válido. Estamos diciendo que la variable T es el tipo de esquema JSON string. Y podemos usar ese esquema JSON que se asigna a la variable T en cualquier lugar donde usemos esquema JSON, en cualquier nivel de validación o serialización.
Pero en esa última línea del ejemplo, puedes ver type T igual a static y luego el parámetro genérico tipo de T, que es esa constante declarada en la segunda línea. Y ahora ese tipo T es un string. La biblioteca TypeBox es lo suficientemente inteligente como para derivar el tipo de un esquema JSON en esa forma estática. Y así, en un ejemplo más complejo, redefinamos nuestro esquema de cuerpo usando TypeBox. Puedes ver que comenzamos con type.object y luego hemos enumerado nuestras seis propiedades, id y name, de tipo string, y luego employed, company, age y projects son todos de tipo opcional. Y luego, dentro de esos tipos opcionales, definimos type Boolean para employed, string para company, number para age. Y en projects, puedes ver que estamos usando type string dentro de type array, que es la forma de TypeBox de decir un array de strings. Y luego estamos definiendo un tipo T body schema que será igual a la resolución estática del tipo de ese esquema de cuerpo de TypeBox. Y luego, en el último bloque de este código, Fastify.post, puedes ver que ahora estamos usando un parámetro genérico. Es un objeto, un nombre, me gusta llamarlos parámetros genéricos de nombre. Y hemos asignado ese tipo de esquema de cuerpo T a la propiedad de cuerpo de ese parámetro genérico. El sistema de tipos de Fastify transmitirá ese tipo de esquema de cuerpo T a través de la propiedad de cuerpo del objeto de solicitud. Y eso es genial.
4. Validación y Manejo de Errores
Pero aún nos falta un paso clave aquí, pero este código ya lo resuelve. Es el paso de validación. Fastify tiene esta opción de esquema que permite a los desarrolladores verificar los datos entrantes de una solicitud y la forma de la respuesta saliente utilizando JSON Schema. Ese paso de validación ocurre antes de que se ejecute la función controladora. Entonces, si el paso de validación falla, toda la ruta generará un error y devolverá un mensaje de error al usuario diciendo que el cuerpo es inválido.
Ahora hemos tipado la propiedad de cuerpo del objeto de solicitud. Pero aún nos falta un paso clave aquí, pero este código ya lo resuelve. Es el paso de validation. Como puedes ver debajo de la cadena add user, se agrega otro argumento a esta ruta. Y es el esquema y luego el objeto cuerpo y luego el esquema de cuerpo. Y no te confundas. Ese esquema de cuerpo es el JSON real definido, devuelto por la API de TypeBox. Fastify tiene esta opción de esquema que permite a los desarrolladores verificar los datos entrantes de una solicitud y la forma de la respuesta saliente utilizando JSON Schema. Bajo el capó, pasamos eso a otro validador JSON y validamos el contenido en función de los esquemas proporcionados. Ese paso de validation ocurre antes de que se ejecute la función controladora. Entonces, si el paso de validation falla, si el cuerpo de la solicitud entrante no coincide con el esquema que hemos establecido en ese segundo argumento de la función, entonces toda la ruta generará un error y devolverá un mensaje de error al usuario diciendo que el cuerpo es inválido. Y creo que también incluye
5. Type Safety and Validation with Fastify
Dentro del controlador de funciones, Fastify valida la propiedad body utilizando el esquema definido. Esto proporciona seguridad de tipo para acceder a propiedades como body.name. Sin embargo, la seguridad de tipo en tiempo de compilación de TypeScript no se basa en tiempo de ejecución. Con la capa de validación de Fastify, podemos acercarnos a la seguridad de tipo para datos dinámicos. JSON Schema, TypeBox y Fastify juntos son herramientas poderosas.
6. Utilizando Genéricos en el Esquema del Cuerpo de TypeScript
El tipo de esquema del cuerpo es un objeto de tipo T de TypeBox con un genérico de este llamado parámetro genérico. Los genéricos son increíblemente poderosos en la actualidad. Dentro de este controlador de funciones, ahora puedes confiar con mayor seguridad en la seguridad de tipo de tus datos dinámicos, todo basado en el mismo esquema JSON que se utiliza para validarlo al mismo tiempo.
7. Reflexión sobre los resultados de la encuesta
Los resultados de la encuesta muestran que muchas personas están familiarizadas con el tema, pero aún hay algunas que nunca lo han utilizado. El objetivo es que los asistentes lo prueben después de la charla y la sesión de preguntas y respuestas.
QnA
Express Validation and Fastify
Express no tiene validación de esquema JSON incorporada como Fastify, pero puedes usar validadores de esquema JSON similares como middleware. Fastify utiliza AJV como su validador, que es rápido y cumple con las especificaciones.
La primera pregunta de uno de los miembros de nuestra audiencia es de Walker MAA, y él dice, gran charla. ¿Express también puede validar el cuerpo contra un esquema como Fastify? Sí. Entonces, Express, creo, no lo uso como mantenedor de Fastify. Tiendo a usar simplemente Fastify. Creo que no está incorporado en Express, pero hay validadores de esquema JSON muy similares que funcionarán igual que Fastify con Express y que puedes usar como middleware. Y lo bueno de Fastify es que está incorporado, por lo que, por defecto, no tienes que cargar ningún complemento especial. No hay nada que tengas que pasar al servidor. Usará un esquema proporcionado a las rutas. Y en el fondo, usamos un validador llamado AJV, que es otro validador JSON, y creo que hay otra pregunta aquí que pregunta sobre una de las otras opciones disponibles. La mayoría de las personas están familiarizadas con algo como Joy, que proviene del conjunto de herramientas del framework web Happy. Pero para Fastify usamos AJV, que resulta ser el más rápido y cumple mejor con la forma en que se iteran los esquemas JSON.
Comparación entre Joy y Typebox
Joy y Typebox tienen una API similar para construir esquemas JSON, pero Joy también proporciona funciones de validación y serialización. Typebox se enfoca únicamente en la construcción de esquemas JSON y se puede utilizar con cualquier validador JSON.
Using Swagger OpenAPI and JSON Schema
Swagger y OpenAPI se implementan en JSON Schema. Puedes usar sus esquemas JSON para que tus rutas de Fastify sean seguras en cuanto a tipos al implementar un servidor de API.
De acuerdo, genial. La siguiente pregunta es de Zero Carol. De acuerdo, bien, pero ¿por qué no usar Swagger OpenAPI? Esta es una gran pregunta. Esto surge con frecuencia todo el tiempo. La respuesta es más o menos la misma pregunta. ¿Por qué no? Adelante. Swagger y OpenAPI, creo, se implementan completamente en JSON Schema. Todo lo que exportan tiene sus propios bloques de esquemas JSON que puedes usar e integrar en otras cosas, otras herramientas, como los sitios web automáticos de Swagger que ves. Todos ellos están impulsados por los esquemas JSON y eso es exactamente el tipo de cosa que puedes pasar a tus rutas aquí, donde si usas el formato OpenAPI para definir tu API REST, puedes usar esos mismos esquemas JSON para que tus rutas de Fastify sean seguras en cuanto a tipos cuando estés implementando ese servidor de API.
Typebox and TypeScript Interfaces
Typebox es una herramienta que genera tipos de TypeScript y esquemas JSON, eliminando la necesidad de escribir y mantener esquemas e interfaces separados. Al depender de una herramienta como Typebox, te aseguras de que la traducción entre el esquema y el tipo sea precisa y confiable, reduciendo el riesgo de errores e inconsistencias.
Genial. La siguiente charla es después de la tuya, pero primero tenemos una pregunta de Johnny Gat. ¿No es Typebox lo mismo que las interfaces de TypeScript? Sí, lo es. Typebox es una herramienta que generará tipos de TypeScript así como el esquema JSON. Podrías hacerlo tú mismo a mano. Puedes escribir tu interfaz que implemente tu propio esquema JSON. La idea aquí es clásica de los programadores, no te repitas a ti mismo. ¿Por qué escribir dos esquemas? Además, si haces un cambio en el esquema, debes asegurarte de hacer ese cambio en la interfaz. No hay muchas formas excelentes de validar que la interfaz que escribiste sea realmente correcta. La implementación correcta del esquema JSON. Los usuarios cometen errores todo el tiempo. Entonces, al dejar que una herramienta haga esa traducción y convierta el esquema en un tipo o viceversa, o ambos al mismo tiempo, eso es mucho más confiable. Sí, agrega una capa de seguridad adicional.
Using JSON Schema for Type Security
La razón por la que animo a la gente a utilizar JSON Schema en lugar de simplemente pasar una interfaz de tipo a su ruta es porque Fastify validará lo que estás proporcionando un tipo y es ese paso de validación el que proporciona la seguridad de tipo que estás utilizando TypeScript en primer lugar. Otra pregunta de David Lime, ¿se podría utilizar TypeBox para generar OpenAPI también? Creo que podrías encontrar algún nivel de interoperabilidad allí donde podrías definir tus objetos o esquemas OpenAPI utilizando TypeBox y utilizar ese esquema JSON donde quieras utilizar tu esquema OpenAPI. Tenemos otra pregunta de Marnice preguntando si hay algo similar a TypeBox para el front-end. TypeBox u otras APIs similares deberían funcionar en el front-end. Todo depende de las herramientas JSON que tengas.
Entonces, otra pregunta de David Lime, ¿se podría utilizar TypeBox para generar OpenAPI también? Gran pregunta. No estoy muy familiarizado con OpenAPI, pero creo que sí. Creo que podrías encontrar algún nivel de interoperabilidad allí donde podrías definir tus objetos o esquemas OpenAPI utilizando TypeBox y tener ese esquema JSON para usar donde quieras utilizar tu esquema OpenAPI y tener los tipos resultantes. Lo único que diré es que creo que con OpenAPI, una gran parte del objetivo es obtener ese objeto JSON como su propio archivo y luego pasar ese archivo. Donde TypeBox, solo lo devuelve durante el tiempo de ejecución. Está en el código. Dicho esto, es JSON en una variable. Puedes convertirlo completamente en una cadena y escribirlo en un archivo. Pero ese segundo paso de operación podría ser un poco diferente a lo que muchos usuarios de OpenAPI están acostumbrados. De acuerdo. Creo que esa es la última pregunta que tenemos en este momento. Tenemos otra. Esta pregunta es de Marnice. ¿Conoces algo similar a TypeBox pero para el front-end? TypeBox u otras APIs similares deberían funcionar en el front-end. Todo depende de las herramientas JSON que tengas. TypeBox es solo un módulo de JavaScript que tiene una API funcional muy fácil de usar que devuelve un objeto JSON. No creo que esté utilizando nada especial de Node.js. Si lo está, creo que la interoperabilidad con el navegador estaría bien. De memoria, no sé si TypeBox se puede usar directamente en un navegador. Debería estar bien. Si no, definitivamente hay otras herramientas alternativas que podrían serlo. O se aceptan solicitudes de extracción. Sí, exactamente. Alguien agradable. Si no tienes nada que hacer durante el fin de semana, puedes probarlo en tu front-end.
Conclusion of Q&A Session
Excelente charla, Ethan, mi favorita hasta ahora. Muchas gracias por tu excelente charla y esta sesión informativa de preguntas y respuestas. No olvides que Ethan estará en su chat espacial si tienes más preguntas para él.
Y con eso, me gustaría terminar esta sesión de preguntas y respuestas. Muchas gracias por tu excelente charla y esta sesión informativa de preguntas y respuestas y espero verte nuevamente pronto.
Por supuesto. Gracias a todos. Que tengan un buen día. No olvides que Ethan estará en su chat espacial si tienes más preguntas para él. Adiós. Adiós.