logo

midudev


Transcribed podcasts: 146
Time transcribed: 5d 6h 19m 9s

This graph shows how many times the word ______ has been mentioned throughout the history of the program.

Vale, hasta ahora hemos visto queries, hemos visto peticiones, ¿cómo podemos extraer datos? Pero bueno, yo creo que lo interesante donde está parte de la amiga muchas veces en realidad está en que queremos cambiar datos. En el caso de GraphQL, el cómo se cambian los datos tiene un nombre bastante particular y que puede causar confusión a veces, que se llama mutación.
Y esto no quiere decir que vas a transformar el objeto en lobezno ni nada de esto. Una mutación al final lo que quiere decir es que cambias algo, que se está cambiando algo. En este caso, cuando hablamos de mutaciones es que vamos a cambiar los datos.
Así que tenemos queries y tenemos mutations, que son mutaciones, que queremos cambiar datos. Así que vamos a hacer una forma que podamos añadir personas a este listín telefónico. Vamos a hacer una forma de añadir personas.
¿Cómo lo podemos hacer? Vamos a hacerlo paso a paso para ver todo lo que necesitamos. Como siempre, todo lo que quieras hacer de queries, de todo, todo lo que tienes que hacer de tus datos y eso, siempre lo tienes que definir antes.
Así es como funciona GraphQL, todo se tiene que definir. Así que si tienes mutaciones, igual que hemos definido las queries, pues ya te puedes imaginar que hay que definir también las mutations.
Así que decimos que el type mutation vamos a añadirle una mutación. La mutación va a ser añadir persona. Ya hemos visto cómo se añaden justamente los parámetros.
El findPerson era así, pues cuando queramos añadir una persona, vamos a pasarlo también por parámetros. ¿Qué parámetros tiene? Pues una persona tiene un string, que es el nombre, es obligatorio, por supuesto.
El font no es obligatorio, como hemos visto, porque ya no tiene. Tenemos el street, que este sí que es obligatorio y por otro lado tendríamos el city, que también es obligatorio.
Fíjate que el mutation, esto lo podemos hacer de un montón de formas, pero en este caso el mutation estamos siguiendo el pasarle el street y el city por parámetro en el mismo nivel.
Cuando luego, cuando hagamos la consulta, lo haremos de otra forma distinta. Y esto es interesante porque luego además la mutación, normalmente lo que haces es devolver la persona que has añadido en este caso,
o la que has modificado o lo que sea. En este caso, cuando añadimos la persona, lo que va a devolver es la persona que ha añadido. ¿Vale?
Esto ayuda para un montón de temas. De hecho, Apolo trabaja mucho con el tema de la caché y te ayuda en este caso para guardar ese nuevo resultado en la caché local,
mientras también lo refleja en la base de datos. En este caso lo vamos a hacer así. No le añadimos una ID porque esto lo vamos a hacer obviamente en el servidor.
¿Vale? No lo vamos a dejar que el cliente nos pase una ID y ya está. Así que vamos a instalar el paquete este UID.
¿Vale? Voy a volver a levantar el servidor. Y vamos a utilizar el UID. Vamos a importarlo por aquí. Import from UID. Y vamos a ver. Creo que tiene aquí la versión 1.
Vamos a hacerla así. Vamos a sacar la versión 1 como que puede ser cualquiera. Como UID y con esto generaremos la ID.
¿Cómo se genera la mutación? ¿Cómo hacemos la mutación? Que es bastante interesante cómo se hacen las mutaciones.
Igual que tenemos aquí Query. Pues ahora tenemos el Mutation. Y del Mutation pues le tenemos que decir cómo se hace el de AddPerson.
Al final los resolvers es justamente esto, ¿no? Cada uno de ellos hay que decir qué es lo que tiene que hacer y cómo lo tiene que resolver cuando le llega esta información.
Pues el AddPerson tenemos el root, tenemos los arcs. Y ahora tenemos que justamente añadir a partir de los arcs esta nueva persona.
Vamos a tener en arcs vamos a tener la persona que va a sacar pues todos los argumentos que aquí tendrá pues el name, le debería llegar el name, el font, el street, el city.
¿Vale? Lo hacemos así con el spread operator. Y además debería tener la ID que se la vamos a generar llamándole UID.
¿Vale? Para que nos cree un identificador único.
Para el que no sepa, UID. No sé si no lo conocéis. Pero básicamente lo que te da son identificadores único.
Tiene diferentes niveles que cada uno pues tiene un coste de... Es que tiene menos colisiones, pero tiene más coste, ¿no?
Por ejemplo, uno está... Depende del timestamp, del tiempo, que normalmente no es tan fiable.
Otro pues utiliza MD5, otro más random, otro SHA-1 y tal. O sea que hay diferentes formas de hacerlo.
Pero bueno, es bastante bien. Sería algo similar a esto, la ID que nos va a dar.
Así que por eso utilizamos este. Y además no debería colisionar pese a que vayamos haciendo.
Tiene una colisión muy baja. No es imperceptiva, pero muy baja.
Ahora lo que podríamos hacer... Podríamos hacer un push del Persons. Podríamos hacer un montón de cosas.
Bueno, podemos hacer un push directamente. En este caso lo hacemos así, ¿eh?
Pero si tuvimos una base de datos, pues lo haríamos de otra forma.
Hacemos un push de la persona y devolvemos la persona.
Lo que estamos haciendo es como actualizar la base de datos.
¿Vale? Que Persons.push, esto sería update database with new person.
De hecho, más adelante además veremos cómo podemos hacer esto con base de datos.
Esto es como la primera iteración, pero luego veremos cómo podemos utilizar MongoDB para hacer todo esto que estábamos haciendo.
Lo veremos en una clase. O sea que no os preocupéis que vais a salir expertos de GraphQL.
Vamos, pero expertos, expertos.
Ya que tenemos la mutación, fijaos. Añadimos la persona, recuperamos de arcs.
En arcs, pues tendríamos que tener, para que veáis claro, name, el font, el street y el city.
¿Vale? Esto lo tenemos en arcs.
Lo que pasa es que, como lo tenemos así, pues podemos utilizar el spread para que todas estas propiedades entren aquí.
Le añadimos la id y esta persona es la que vamos a empujar al array de esta forma.
Esto es porque lo tenemos esta base de datos local.
Y devolvemos la persona.
Guardamos los cambios y nos vamos justamente a nuestro playground querido.
Y vamos a hacer esta mutación.
Vamos a hacer un mutation, los brackets, addPerson y le pasamos los parámetros que necesita.
¿Qué parámetros necesita? Pues el name.
Voy a mirar el chat y vamos a buscar un nombre.
Vamos a ver.
Venga, a borja25, que además está haciendo la pregunta.
A borja25.
¿Vale?
Ay, esto no se puede hacer con comillas simples, se tiene que hacer con comillas dobles.
Venga.
Font y vamos a tener el 123 y de 123 vamos a ponerle también street, que vamos a poner que sea por qué no usar require, que es la pregunta que me estaba haciendo.
Y city vamos a ponerle albacete, aunque no tengo claro que sea de allí.
Esto sería para hacer la mutación, pero hemos dicho, de hecho voy a darle al play, ¿vale?
Vale.
Fíjate que nos da un error.
Porque me dice que al añadir una persona tenemos que tener una selección de subcampos.
¿Otra vez?
¿Por qué?
Bueno, porque la mutación addPerson lo que tiene justamente es que le hemos dicho que devuelva a una persona y por lo tanto necesitamos también extraer los campos de esa persona.
Así que nada, vamos a poner aquí otra vez los brackets y miramos.
Si vamos a control espacios que ya nos va diciendo, ¿ves?
Name, font y podemos sacar lo que queramos.
Pero fíjate que como lo que nos está devolviendo es de tipo persona, aunque nosotros le añadimos la dirección de esta forma, nos la está devolviendo con el tipo que tenemos definido.
Hay que sacarlo así.
Y esto sería justamente toda la persona que hemos añadido nos debería devolverla.
Vamos a darle al play y ya tendríamos aquí.
Ha hecho un addPerson con este nombre, con este teléfono, con la dirección.
Así que con esto ya habríamos hecho nuestra primera mutación.
En GraphQL, una diferencia bastante interesante de GraphQL respecto a REST, por si no he comentado antes, pero todas estas peticiones que estamos haciendo aquí,
tanto las mutaciones, mira, de hecho podemos tener aquí pestañas.
Vamos a poner el person count, ¿vale?
Fíjate, yo hago esta petición y puedes copiarte aquí el curl, ¿vale?
Vamos a copiarlo, me voy a ir a terminal y lo voy a pegar aquí, por ejemplo.
Y lo voy a poner y tal, mira, el curl.
De hecho, esto lo podríamos ver ahora con Postman o algo así.
Es que la diferencia que tenéis con una REST API es que una REST API y lo que tenemos siempre son un montón de URLs diferentes para recuperar diferentes recursos.
Pero en este caso, fíjate, si me copio para hacer esta request, esta es la URL, localhost 4000.
Hago esto y ya me devuelve esto.
Si, por ejemplo, me hago otra query que me devuelva a todas las personas y de todas las personas el nombre, ¿vale?
Esta query funciona.
Me copio esta petición, la hago aquí.
Y fíjate, siempre va a la misma URL.
Solo tienes un endpoint.
Solo tienes un punto de entrada para tu API.
Entonces, no es como el REST API que tienes un montón, ¿vale?
Tú solo tienes que hacer un tipo post a esta URL y lo que le tienes que pasar es esto que vemos aquí, que es esto de aquí, que es la query.
Esta query que tenemos aquí es lo único que le tienes que pasar.
Le pasas la query al mismo endpoint siempre del tipo post.
Entonces, cuando sea una mutación, pues le estarás pasando esa información.
Pero ya no tienes que pensar en delete, post, get, no.
Siempre es un post a un endpoint.
Es totalmente diferente a una REST API.
No tiene nada que ver, ¿vale?
Luego, por dentro, tú puedes hacer lo que sea.
Pero puedes hacer un post, un delete, dentro en nuestros resolvers.
Pero en este punto siempre es el mismo endpoint.
Ah, ¿cómo evitas el null?
¿O cómo realizas las validaciones?
A ver, entiendo que el null como tal no hay que evitarlo, ¿vale?
Me imagino que el que quieres evitar es el que hemos visto antes.
Este, ¿no?
El del find person name y hemos puesto itzy.
Una cosa que está genial, además, es el hecho de cómo de pesado es el playground.
Vale, hemos puesto itzy, pero aquí ya habíamos puesto Pepito y Pepito no...
Este null.
Me imagino que te refieres a este, ¿no?
A este null.
A ver, yo no diría tanto solucionar, porque no sé hasta qué punto la idea sería solucionarlo, ¿vale?
O sea, no sé si se tiene que solucionar, porque al final puedes vivir con esto, ¿no?
Solo que lo tienes que tener en cuenta.
Si no, lo que podrías hacer...
A ver, si aquí al entrar te devuelven un undefined, lo que puedes hacer es devolver un objeto vacío.
Al devolver el objeto vacío...
¿Vale?
Return null for null, fill name...
No.
¿Por qué esto al devolver...?
¿Qué podríamos hacer para devolver esto?
Pensaba que devolviendo un objeto vacío igual colaba.
Claro, pero no puedes devolver un objeto vacío porque el name es requerido.
Como el name es requerido, pues no puedes hacerlo.
En este caso, creo que, claro, tiene sentido que sea un null porque no ha encontrado a la persona.
O sea, tiene sentido, ¿no?
Que se te devuelva un null.
Solo que tenlo en cuenta.
Lo único que tienes que hacer es tenerlo en cuenta.
O sea, al no encontrar la persona que es Pepito, es imposible que te devuelva aquí un objeto que tenga nada.
Pues la persona, al encontrar a la persona, null.
Null en GraphQL es que no ha encontrado los datos o no existe.
O sea, está bastante bien porque siempre te devuelve null.
No verás que te devuelve un undefined y nada.
Siempre tienes null.
Entonces, yo en este caso no veo que se te haga arreglar.
Porque si no, como name, esto es requerido.
Es que lo único que se me ocurre es que hagas cosas así.
It's not defined o not found.
Pero es que no tiene sentido.
No tiene sentido que te pongas a hacer cosas así.
Yo no lo haría, vaya.
Porque ahora es porque he devuelto name.
Pero si ahora pido el street, me volverá a petar.
Otra cosa que puedes hacer es devolver una persona por defecto.
¿Sabes?
O sea, tener un default person que tenga name, que lo tenga todo.
Pero yo, es lo que os he dicho antes.
Que con que lo tengáis en cuenta, que no siempre, si no encuentra la persona, devuelve null.
Que no vais a tener la opción de ir a name.
Y por lo tanto, lo que podéis hacer es aquí acceder a algo así.
Person.name.
Pues name.
Y con esto lo tendríais.
Yo haría eso.
Vaya.
Esa es mi recomendación.
Claro, yo lo manejaría desde el cliente.
GraphQL no es una base de datos.
¿Vale?
No tiene nada que ver con una base de datos.
O sea, no se mete.
¿De dónde tienes tú los datos?
Es indiferente.
O sea, es indiferente.
Y luego, la pregunta es, ¿se prefiere utilizar REST API antes que GraphQL?
Es que tampoco, no es antes.
O sea, es que es esto.
O sea, GraphQL puedes llamar a REST APIs.
O sea, no son, al final, no son antagonistas como tal.
¿Vale?
No son antagonistas.
O yo no lo veo así.
¿Vale?
Venga, vamos a darle cañita que nos quedan las validaciones, manejo de errores.
Bueno, validaciones son los manejos de errores.
Así que, hemos visto la mutación, ¿vale?
Hemos mutado aquí.
El problema que tiene la mutación es que yo me puedo poner aquí con el Aborja 25.
Por cierto, me preguntaba que por qué no uso Require.
Y no uso Require porque estoy utilizando el Macri Modules porque hemos añadido el Type Module en el Package JSON.
Y así utilizamos import.
Y porque los Require deben desaparecer de la faz de la tierra.
Así que si puedes, deja de utilizar Require en tus proyectos de Node.
Si no puedes, pues sigue utilizándolos.
Pero desaparecerán en algún momento, ¿vale?
Vale.
Ahora que ya tenemos esto, que hemos visto justamente que podemos hacer mutaciones y tal.
Yo podría seguir añadiendo aquí todo el rato a esta persona.
Y fíjate que la ID va cambiando, ¿verdad?
Que va cambiando esto porque estoy añadiendo a Borja 25 todo el rato, todo el rato, todo el rato.
Así que tenemos que añadir algún tipo de control, alguna validación para que esto no ocurra.
Para no añadir a personas que siempre tenga el mismo nombre.
A ver, que puede, esto es el mismo nombre, en realidad sí que podría ocurrir personas del mismo nombre.
Pero vamos a evitarlo solo para ver cómo sería el tema de las validaciones.
Tengo por aquí justamente cómo sería el error handling.
Hay diferentes errores o códigos de error que puedes tener en GraphQL.
Por ejemplo, si, bueno, este suele ocurrir más automáticamente.
Si la operación tiene algún problema de sintaxis, esto lo suele hacer.
Si va en contra del esquema, esto también lo hace automáticamente.
Pero tú puedes añadir algunos que consideres.
Por ejemplo, un user input error.
Esto lo podríamos añadir nosotros.
De hecho, lo vamos a utilizar para el error que nosotros vamos a hacer.
Pero si nosotros aquí en el playground, pues por ejemplo, quitamos el city y le doy aquí a play,
aquí ya tenemos un error.
Y ves, GraphQL validation fail, que es justamente el que estaba diciendo aquí.
GraphQL validation fail.
Este es un error que siempre vas a tener en el caso de que esta operación vaya en contra del esquema que le hemos dicho.
¿Por qué?
Porque en el esquema dice que ese campo, mira, es que te lo dice.
Es que el playground es una maravilla.
Está requerido y por lo tanto, pues no funciona.
Lo mismo, la sintaxis.
Claro, si yo me invento la sintaxis, pues bueno, ahora de hecho ni siquiera funciona.
Pero si nos inventamos la sintaxis, también nos debería dar problema de la sintaxis.
Entonces, yo lo que quiero es controlar que estemos añadiendo siempre la misma persona.
¿Cómo podemos hacer esto?
Vamos a hacerlo paso a paso.
Vamos a nuestro resolver.
Vamos a nuestro resolver de la mutación.
Y aquí, al añadir una persona, lo primero que vamos a hacer antes de nada es, vamos a hacer un if,
a ver si esta persona, vamos a ver si esta persona, persons.find, si esta persona, vamos a ver si en el array de personas
tenemos una que el nombre sea exactamente igual al nombre que nos está pasando por los parámetros.
Y aquí lo que podemos hacer es un if y en el if, pues podríamos hacer un throw new.
Aquí podríamos poner un error, normal y corriente.
Vamos a ver, name must be unique.
Y ya está.
En este caso, vamos a ver si esto funciona tal cual.
A ver.
Vale.
Esto funciona, pero fíjate que el error que dice, vale, mensaje sí, el nombre tiene que ser único,
pero internal server error.
Lo que ha pasado aquí es que he añadido uno, ha ido bien, he añadido otro, me ha dado este error.
Pero este error, este internal server error, hombre, es bastante, de hecho, no sé si habrá,
ah, no, que he abierto Discord sin querer, no, quieto.
Vale, ya está.
Seguramente aquí no aparece, pero aquí este error de internal server error da bastante grima.
Así que vamos a hacer un error un poco más descriptivo.
Lo que podemos hacer aquí en Apolo Server, vamos a añadir el user input error,
y este user input error es como para decirle, esto ha sido culpa tuya, que has hecho algo que no debías.
En lugar de hacer un throw new error, vamos a utilizar este,
y además le podemos pasar un segundo parámetro para indicarle dónde está el problema.
Le podemos decir invalid args, y le podemos decir que es el args.name.
De esta forma estamos controlando mejor que no podamos añadir, pues,
una persona que tenga otra vez el mismo nombre.
Vamos a ver aquí, si ahora refresco, añadimos una vez, vale, ha funcionado bien una vez.
La segunda, vale, ahora ha petado, pero fíjate que el código ahora es bad user input,
y nos está diciendo en la excepción que el invalid arg, pues, ha sido esto.
Así que le estamos dando una información un poquito mejor.
Hay diferentes error handling, por ejemplo, si no está autentificado,
no sé si llegaremos, veremos si...
Igual sí que vemos.
Igual sí que vemos de iniciar sesión, lo veremos, no en la clase siguiente,
sino en la siguiente.
Pero hay diferentes errores que puedes utilizar.
Este sería el que es por defecto, pero bueno, no es el que te recomiendo.
Siempre que puedas, pues, intenta ser lo más correcto posible.
Ahora, vamos a...