This graph shows how many times the word ______ has been mentioned throughout the history of the program.
Esta sería la tercera clase, aunque hoy vamos a estar haciendo desde cero nuestra primera API REST.
Te voy a explicar qué es un API REST, por qué es diferente a cualquier API.
La vamos a estar creando, los problemas que nos podemos encontrar, vamos a hacer validaciones,
vamos a estar devolviendo diferentes casos.
Te voy a explicar una forma de validar, de forma bastante, creo que fácil y correcta, las cosas,
cómo separar esas validaciones.
También vamos a ver el temido problema de CORS, que a todo el mundo, todo el mundo,
yo creo que es una de las preguntas más repetidas en el mundo de la programación y el desarrollo.
¿Por qué no me funciona el CORS?
Fijaos una cosa, hace, relativamente hace poco, puse en LinkedIn y en Twitter una pieza donde explicaba el problema de CORS
y tenía un montón de gente que me estaba echando hate.
Yo decía que no era correcto, que no se arreglaba en el backend, que no sé qué.
Pues hoy lo voy a demostrar, hoy lo voy a demostrar y hoy vais a ver,
y vais a entender cuál es el problema de CORS, cómo se soluciona, cómo funciona y por qué no es tanto problema.
Hoy vamos a utilizar este de aquí, que se llama FL0.
¿Por qué? Porque este sí que tiene un free tier, al menos de un proyecto, que algo es algo.
Un proyecto totalmente gratis, que obviamente tiene algún tipo de limitaciones de memoria y tal,
pero no tiene limitaciones de cuánto tiempo puede estar encendido el servicio.
O sea, que puede estar encendido 24-7 y además sin ningún límite de transferencia, que lo pone aquí.
Tiene bastante buena pinta, lo vamos a hacer desde cero.
Y lo más importante, que es lo que está diciendo Feral, no pide tarjeta de crédito,
que sé que es una cosa que muchas veces os echa para atrás con razón de tener que meter la tarjeta de crédito para el free tier.
En este caso no lo hace, no lo pide, lo sé porque yo me he registrado y no lo pide.
Y luego lo vamos a estar probando, lo vamos a hacer y todo esto.
Me gustaría ver las configs de CORS en acción.
Vamos a ver una configuración de CORS porque vamos a hacer el CORS nosotros desde cero, ¿vale?
Para que lo entendáis bien.
Si os habéis perdido alguna clase de este curso de Node.js y queréis aprender Node.js desde cero,
¿veis? Clase 1, clase 2, clase 3.
Todas estas clases las estamos poniendo aquí y aquí tenéis todos los vídeos de las clases
con introducción a Node.js y sus módulos.
Creamos una API desde cero y hoy la API Res.
Aquí tenéis el repositorio.
Fijaos que ya tenemos la clase 3 aquí preparada
y en la clase 3 he puesto un archivo, movis.json.
Voy a abrir ya este pedazo de repositorio.
Aquí en la clase 2 lo último que hicimos es que estuvimos trabajando con Express, ¿no?
Y en Express creamos un servidor web, os expliqué cómo crearlo paso a paso,
importar la dependencia, que podíamos traer JSON y devolverlo,
archivos estáticos, podíamos desactivar la cabecera del xPower
que ya dijimos que por un poquito de temas de seguridad era importante, ¿vale?
Vimos cómo podíamos escuchar el body, o sea, recuperar los datos
cuando se hacía un post en nuestra API, en nuestro backend
y luego lo simplificamos gracias al middleware de Express.json, ¿no?
Y lo explicamos paso a paso y tal.
Y lo dejamos un poquito aquí.
Es verdad que hicimos un poquito, eso expliqué también un poco los middlewares y todo esto,
pero no llegamos a hacer una API Res.
Así que hoy vamos a hacer una API Res basada un poquito en esto.
Vamos a empezar nuestra API Res paso a paso, uno tras otro.
Si os parece, yo creo que lo primero que podríamos hacer sería más bien empezar con nuestro servidor.
Así que vamos a empezar aquí en la clase 3 para que así la gente además,
que por lo que sea no estuvo, pues mira, que pueda reengancharse, ¿no?
¿Cómo creamos nuestro primer servidor?
Bueno, pues lo que he dicho antes.
Express, Require, Express.
Utilizamos Require porque por ahora estamos utilizando CommonJS,
pero ya os informo, en la siguiente clase vamos a pasar a utilizar EnmascrimModules.
Y os explicaré algunos de los problemas y retos que podemos encontrar,
pero que vale la pena porque yo creo que es lo que hay que utilizar ahora, ¿vale?
Entonces, constante AppExpress.
Creamos nuestro Express y aquí le decimos que vamos a utilizar...
Bueno, esto no lo necesitamos, así que no lo vamos a poner.
No lo necesitamos.
Por ahora lo que voy a hacer es que desactivemos el PowerBy, ¿vale?
Esto quita, exacto, deshabilita el header XPowerByExpress.
Esto es una cabecera que cuando tú haces una petición a esta API, aparecerá.
Es como una forma de hacer publicidad gratis de Express.
Es como cuando te compras una camiseta de Nike y aparece aquí el logo de Nike en grande.
Pues esto es básicamente lo mismo y se puede desactivar.
Con Nike no lo puedes hacer.
Lo primero, pues ya podríamos decirle, oye, cuando se haga el método GET en la raíz,
pues vamos a contestar, vamos a ejecutar este callback y ahora, pues nada, fácil, ¿vale?
Vamos a poner aquí hola mundo, ya está.
Vamos a escuchar en el puerto que sea el processenv.port o si no, vamos a ponerle por defecto un, dos, tres, cuatro.
Le puedes poner el que tú quieras.
Y vamos a escuchar que nuestra aplicación escuche en este puerto y aquí el típico mensaje de servidor
escuchando en el puerto tal, tal, tal.
Con esto ya tienes tu API, pero obviamente ahora tenemos que hacer unas cuantas cosas.
Mira, vamos a levantarla.
Vámonos a clase 3.
Vamos a inicializar el proyecto porque fíjate que aquí en clase 3 no tenemos un package JSON, ¿verdad?
Voy a hacer un npm init menos i y ahora sí, pues puedo hacer aquí npm install express menos e, ¿vale?
Para que nos instale la versión exacta.
Si no le pones nada, pues te va a poner el caret, que ahora te enseñaré lo que es.
Y si le pones menos e, no te pone el caret.
Mira, el package JSON, ¿ves?
Ahora me ha instalado aquí la dependencia.
Y fíjate que no me ha puesto el cosito, esta cosa.
Esto se le llama, a este símbolo, se le llama caret.
Entonces, este caret tiene implicaciones de la versión que instalaría.
Y nosotros normalmente vamos a evitar ponerlo.
Así que, pum, lo dejamos así.
Si queréis que esto lo haga automáticamente, pues ya sabéis, menos e mayúscula para poner la versión exacta.
Ahora que ya tenemos esto, pues nada, node con el watch, que esto lo aprendimos en una de las clases.
Y aquí, pues vamos a levantar app.js.
Esto, ¿veis?
Ya se ha levantado.
Nos da el warning, la advertencia de que el modo watch es experimental.
Aunque ya os digo que le queda muy poco de experimental.
Y yo lo recomiendo porque funciona muy bien.
Y ya está escuchando en el puerto 1, 2, 3, 4.
Ya lo sabéis, ¿no?
Todo esto lo tenéis bien, ¿sí?
Bien.
Hoy, amigos y amigas, vamos a hablar y vamos a crear una REST API.
¿Qué es una REST API?
Una REST API, para que todo el mundo lo sepa.
REST es el acrónimo de Representational State Transfer.
Y REST es una arquitectura de software.
Importantísimo tener en cuenta que es una arquitectura de software.
No es un framework, no es una biblioteca, no es una idea, no es un patrón.
Es una arquitectura, ¿vale?
Una arquitectura de software.
Se diseñó en su día para sistemas de comunicación en redes, especialmente aplicaciones web.
Y nació el año 2000, ¿vale?
El año 2000, por Roy Fielding.
Y entonces, se ha utilizado para muchas cosas, pero especialmente, esto sería REST, ¿vale?
Esto sería REST, más que REST API.
Esto sería REST, ¿vale?
¿Y dónde se ha utilizado este tipo de arquitectura?
¿Dónde mucho, mucho, mucho, mucho?
Bueno, se ha utilizado para, sobre todo, construir APIs.
Y a partir de aquí, pues hemos tenido la REST API, ¿vale?
Pero al final, como son comunicaciones en redes, podríais entender que el tipo de comunicación
y los principios en los que está basado la escalabilidad...
Vamos a hablar de REST API todo el rato, para no liarla.
Y vamos a poner aquí que REST es una arquitectura de software.
Vamos a redondear esto y vamos a poner los principios en los que se basa REST.
Por ejemplo, la escalabilidad, simplicidad, visibilidad, portabilidad y la fiabilidad.
Me falta uno, bueno, que sería la modifica, fácil de modificar.
Normalmente, todas las arquitecturas de software, hay mucha gente que a lo mejor no sabe que REST es una arquitectura de software.
Pero todas las arquitecturas de software responden a crear, a base de unos principios, ¿no?
La idea de poder crear algo que pueda sostenerse en el tiempo de la mejor forma posible, ¿vale?
Y simplificar el desarrollo de esa pieza de software.
Para eso son todas y cada una de las arquitecturas del mundo, ¿vale?
Todas las arquitecturas están basadas en esas ideas.
En ideas de, oye, vamos a tener una serie de principios y vamos a tener unos fundamentos
que hay que seguir para poder conseguir utilizar esta arquitectura.
Hay un montón de arquitecturas que seguramente luego iremos viendo patrones y arquitecturas
para que os deis a la idea, pero vamos a ver cuáles son los principios fundamentales de REST
para considerar que estás utilizando REST.
Lo primero, cuando estamos hablando de REST, esos serían como los principios,
pero ¿cuáles serían los fundamentos?
Vamos a hablar de resources, ¿vale?
En español sería recursos.
Vamos a hablar de recursos.
Y los recursos, que lo vamos a ver luego en código, ¿eh?
O sea, que no te asustes.
Vale, los recursos en REST, en una arquitectura REST, todo es considerado un recurso.
Que puede ser una entidad concreta, yo que sé, por ejemplo, un usuario, un libro,
una publicación de un blog, una imagen, un recurso puede ser algo.
O puede ser una colección de estos recursos.
Puede ser una lista de usuarios, una lista de libros, una lista de lo que sea.
Cada recurso, y esto es súper importante, cada recurso se va a identificar con una URL.
Y esto es súper importante, y lo vamos a ver luego cuando veamos el código, todo esto lo vais a ver más claro.
Pero es importante un poquito de lógica, de teoría, para que entendamos después, ¿vale?
Entonces, los recursos.
Cada recurso se identifica con una URL.
Y ya os digo, que en REST todo está considerado como un recurso, que pueden ser entidades concretas o colecciones de entidades.
Luego tendríamos otro fundamento.
Y el otro fundamento serían los métodos o los verbos.
En este caso, vamos a estar hablando más de REST API, así que vamos a hablar de verbos HTTP, ¿vale?
Los verbos que ya vimos el otro día.
Get, post, put, delete, patch y todo esto, ¿no?
Que son los que se utilizan para definir las operaciones que se pueden realizar con los recursos.
Para definir las operaciones que se pueden realizar con los recursos.
Ya os podéis imaginar que lo que vamos a querer es crear, ¿no?
Estos verbos normalmente representan las acciones básicas de un CRUD.
Que es CRUD, significa create, read, update y delete, ¿no?
Crear, leer, actualizar y eliminar.
Esto lo que te permite es que las aplicaciones puedan, de alguna forma, pues interactuar con estos recursos.
Otro fundamento tendríamos las representaciones.
Las representaciones, ¿qué quiere decir esto?
Muchas veces la gente se confunde ante la idea de que las APIs, todas las APIs, tienen que ser JSON.
Y eso no es así, ¿vale?
No es así.
Hoy lo vamos a ver así, lo vamos a seguir así.
Pero lo cierto es que algo muy importante para el tema de seguir una REST API es que los recursos pueden tener múltiples representaciones.
Y entonces podemos tener la representación que sea así con JSON, esto podría ser, pero podría ser XML, HTML, etc.
O sea, el cliente debería poder decidir la representación del recurso.
O sea, los recursos se pueden presentar en diferentes formatos.
No debería estar atado a uno en concreto.
Pero bueno, ya entendemos y es normal totalmente, ¿no?
Que las representaciones, pues al final, si vas a utilizar JSON, solo hagas JSON.
Pero lo cierto y lo importante es que esté, de alguna forma, totalmente separada la representación del propio recurso.
O sea, si el recurso, que el recurso no sea per se un JSON, sino que lo puedas representar de diferentes formas.
Otro fundamento muy importante es que sea stateless.
Stateless es que cada solicitud que tú haces al servidor debe contener toda la información necesaria para entender esa solicitud.
¿Qué quiere decir?
Que el servidor no debe mantener ningún estado sobre el cliente entre solicitudes.
Esto es otro error que he visto muchas veces.
Y entonces ya no está siguiendo la arquitectura de REST.
Esto lo que quiere decir es que el servidor no puede, no puede, ni necesita, ni tiene que hacer nada que guarde información para poder saber responder qué tiene que decirle al cliente.
Por ejemplo, no puede guardar cuántas llamadas se han hecho, si tiene que paginar o no tiene que paginar.
No, esa información siempre tiene que ir en la URL, en la petición que le estamos haciendo, para que el servidor solo con esa URL ya sepa lo que tiene que hacer.
No tiene que tener un estado.
Esto es algo que muchas veces hacemos de forma automática, para bien, pero es fácil a veces cometer el error de guardar algún tipo de estado para que nos ayude y tal.
Pero entonces estamos justamente ya rompiendo los principios de la REST API.
Súper importante que lo entendáis, ¿vale?
El cliente debería siempre enviar toda la información para procesar la request, ¿vale?
El servidor no necesita tener ningún tipo de estado para procesar la request.
Que esto no quiere decir que no tenga base de datos o todo este tipo de cosas, ¿vale?
Eso no significa que no puedas tener una base de datos donde guardar información.
Lo que quiere decir es que nuestro backend no debe guardar información para saber cómo tiene que contestar esta request.
Y finalmente tendríamos, esto tampoco pasa nada, os lo puedo comentar también,
el tema de que tenga una interfaz uniforme, ¿no?
Que la interfaz entre el cliente y el servidor tiene que ser consistente y uniforme para todas las interacciones.
Que obviamente, o sea, es importante.
Es importante, pero esto es muy difícil que lo rompamos.
Básicamente que nuestras URLs siempre tienen que hacer lo mismo, siempre se tiene que llamar igual.
Y a todo esto, otra cosa en la que está esto sustentado,
y es muy importante porque muchas veces me comentáis, y esto es para juniors también,
que yo no entiendo esto, que la gente dice, no, es que esto no sé qué.
Separación de conceptos.
Esto es otro pilar de REST, ¿no?
O sea, los componentes del cliente y del servidor están separados entre sí.
Permite que cliente y servidor evolucionen de forma separada.
Así que estos serían como todos los fundamentos que deberíamos tener con nuestra REST API,
en lo que se fundamenta, ¿vale?
Cómo las tenemos que construir.
Tendríamos aquí un poco lo que es arquitectura de software,
cuándo nació, las palabras clave, los fundamentos de cada una,
y en lo que se sustenta.
Y son estos seis pilares que se sustentan en la REST API.
Ya no tenéis excusa.
Ya sabéis cómo funciona la REST, qué es lo que tiene que cumplir.
Y muchas veces tened en cuenta una cosa que es súper importante, ¿vale?
A veces puedes hacer una API que no sea REST.
Puede ser, ¿vale?
Lo digo porque hay gente que está encabezonada en que todas las APIs son API REST.
Y no lo son, ¿vale?
No lo son.
Hay veces que puedes crear una API que no sea REST.
Hay otros tipos de arquitecturas, otras soluciones.
Tienes SOAP o tienes cosas que ni siquiera son SOAP.
Puede ser que tú hagas una llamada a un sitio, ¿vale?
Sí, ¿cómo?
Pues así, ¿cómo?
Que hay un montón de APIs que no tienen por qué ser REST.
Una API puede ser una API y punto.
No tiene por qué ser REST.
Es que hay un error muy común en la que mucha gente,
cuando ya hace una API que devuelve JSON, le llama API REST.
Y ya está, ¿sabes?
Y no es así.
Obviamente tenéis soluciones tan interesantes como GraphQL.
GraphQL, aunque es un lenguaje en realidad de hacer consultas,
las APIs que puedes crear no son REST API.
¿Ves?
Aquí no te pone a query language for your REST API, que también lo puede ser.
O sea, hay un montón de formas de hacer APIs, incluso aunque devuelva JSON,
que no son REST API, ¿vale?
Muy bien.
Pues venga, vamos al código y vamos a volver, si os parece, a este proyectito.
Vamos a hacer primero los gets.
Ya vimos en la clase anterior que podíamos hacer aquí un API punto HTTP.
Y gracias a esta extensión que tengo por aquí, que se llama REST Client,
gracias a esta extensión, esta extensión es muy chula, te la recomiendo un montón.
Ahora que vamos a estar trabajando un montón, creando APIs y tal.
Esta extensión lo que te permite es tener un archivo terminado con HTTP, ¿vale?
Y aquí podremos poner recuperar todas las películas, ¿vale?
Y aquí vamos a hacer un get de HTTP localhost 1234 barra movies.
Y aquí ya podríamos enviar la request, aunque obviamente, ¿qué vamos a ver?
Pues que esto nos está devolviendo un 404 porque no hemos creado esta ruta.
Vamos a crear algunas rutas, ¿vale?
Y las vamos a ir haciendo y os voy a ir explicando un poco cómo encaja con el tema de REST.
Aquí una película por ID, ¿vale?
Vamos a poner get HTTP localhost 1234 movies, ¿vale?
Y aquí tendríamos la ID, vamos a poner uno por ahora.
Y aquí podremos recuperar todas las películas por un género.
Get HTTP localhost, imaginemos, movies, ¿vale?
Aquí esto es bastante interesante porque fíjate cómo me ha hecho el autocomplete.
Me lo ha hecho así.
O sea, esto está bien porque estaría siguiendo el tema de que todos son recursos.
Los géneros podrían ser recursos porque podríamos recuperar todos los recursos.
Hay diferentes estrategias para hacer esto y dependiendo del nivel de filtros que quieras hacer,
hay veces que vas a querer utilizar directamente query params, ¿no?
Y para recuperar géneros, a lo mejor no lo ves como un recurso, sino que solo lo ves como un filtro
y seguramente puede tener sentido hacerlo así.
Pero bueno, ya veis que hay diferentes estrategias y no es que haya una buena y una mala,
no hay ninguna perfecta, porque todo depende de cómo tú entiendas que son entidades y recursos.
O sea, qué es lo que crees que son filtros y cuáles son los que crees que no lo es.
Y muchas veces depende más de la lógica de negocio, más del producto,
porque no es lo mismo en un producto, una moneda, por ejemplo, un coleccionista de monedas
va a pensar que una moneda tiene un identificador, es una entidad dentro de su negocio,
pero seguramente para una tienda online de camisetas le da igual la moneda que sea,
mientras sea dinero.
Y por lo tanto, lo único que le importa de esa moneda es el valor.
Ya veis la diferencia entre un coleccionista de monedas, que cada moneda va a tener una idea, un tal,
una persona que lo único que quiere del dinero es el valor, ¿no?
Ya veis la diferencia, pues este tipo de cosas son muy comunes
y por lo tanto hay veces que podemos entender entidades de forma distinta, ¿vale?
Yo lo voy a poner aquí como query param, porque además me ayuda a también explicaros
alguna forma de, algunas cositas.
Y lo que vamos a estar creando de esta REST API, fijaos, es este books.json.
Este books es movies.json, perdón.
Aquí tenemos diferente información, tenemos películas con título, año, director, duración.
Y esto, la semana que viene, lo vamos a volcar a una base de datos.
Y todo lo que hacemos hoy, lo vamos a pasar para que funcione con base de datos, ¿vale?
Así que esto es lo que vamos a estar sirviendo, creando, modificando y todo esto.
Vamos a crear esto de recuperar todas las películas.
Fácil.
¿Qué tenemos que hacer?
Pues vamos a hacer app.get barra movies, ¿no?
Porque cuando queremos acceder, hemos dicho, fijaos, esto tenemos los recursos.
Y cada recurso se identifica con una URL.
¿Cuál es la URL que queremos identificar?
Pues barra movies.
Así que ahora ya sabemos que todos los recursos que sean movies se identifica con barra movies.
O sea, ya tenemos una URL que identifica a este recurso en concreto.
Si queremos recuperar las películas, vamos a hacer barra movies.
Y aquí vamos a responder que cuando pidamos esto, pues nada, más que el JSON de esto, vamos a importar el movies.json.
Y lo único que tenemos que hacer aquí, por ahora fácil, es devolver todas las películas.
Así que hacemos un res.json movies.
Con esto al menos ya tendríamos este de aquí, ¿no?
Fácil.
Este es fácil, ¿ves?
Ya hacemos la request y ya nos está devolviendo aquí todo el JSON con todas las movies y tal.
Como hemos visto, en realidad la representación, ese cliente debería poder decidir la representación del recurso.
Yo esto, la verdad, lo he visto muy pocas veces, pero es verdad que alguna vez lo he visto.
Pero no hay que entenderlo como que siempre podría hacerlo, aunque no sería imposible.
O sea, podríamos siempre poder escuchar aquí, yo que sé, y esto sí que lo he visto en alguna API,
donde podamos leer el query param de output o de format, ¿vale?
Y en el de formato aquí podamos decir, vale, si el formato es HTML, pues vamos a devolver,
en lugar de esto, vamos a devolver la lista con un HTML.
Si es XML, pues vamos a transformar el JSON y tal.
Sí que lo he visto en algunas APIs, pero para APIs internas y tal no lo he visto tanto.
Y aún así me parece un poco muy estricto hacerlo, porque al final si solo te interesa JSON,
creo que tampoco pasa absolutamente nada, ¿vale?
Pero para que te hagas un poquito la idea.
Ya tendríamos el primero, recuperar todas las películas.
Ahora, recuperar una película por ID.
Pues aquí vamos a ver una cosa muy interesante sobre Node.js, que además está bien que entiendas y que veas, ¿no?
A ver, voy a quitar esta, que esta no añade nada.
Ya hemos creado un endpoint, que un endpoint, para lo que sepas, sería un path en el que tenemos un recurso, ¿no?
Un endpoint, las APIs tienen diferentes URLs a las que podemos llamar para extraer información.
Se le llaman endpoints justamente porque es el final de la API a la que vamos a poder acceder para recuperar esa información.
Así que esto ya sería el endpoint para el GET, ¿vale?
Con el verbo GET.
Para recuperar una película, podemos utilizar a .get barra y creamos un nuevo endpoint.
Barra movies, barra, dos puntos y de.
Y vamos a ver esto porque esto es una de las magias más importantes de Path to Regex, de Express.
Esto que estamos haciendo aquí, a esto se le llama que es como un segmento dinámico y son los parámetros de la URL.
¿Qué significa esto de ser un parámetro de la URL?
Es completamente normal que muchas veces, si vamos a una página web, por ejemplo esta, ¿no?
Vamos a .medudev, ¿vale?
Cuando vas a .medudev y entras a un artículo, fíjate que esta parte de aquí siempre tiene que ver con el artículo.
¿Veis que es el artículo?
Entonces, esto de aquí podríamos entender que es el ID del artículo, ¿vale?
No sé si lo veis, pero lo hago así de pequeño.
ID del artículo.
Es el ID que identifica a este artículo.
Y claro, no podemos poner manualmente aquí todas las IDs porque no las sabemos antes de su creación.
Y las IDs pueden cambiar y tal.
Y además, necesitamos de alguna forma capturar esa ID para poder acceder a ella después.
Entonces, lo que le estamos diciendo aquí a Express es básicamente, oye, en barra movies, barra, aquí le vamos a pasar una ID y además quiero después poder acceder a ella.
Poder escucharla, o sea, poder recuperarla, leerla y todo esto, ¿no?
¿Y cómo lo podemos hacer?
Pues una vez que ya hemos hecho esto, este segmento dinámico que además podéis poner más.
Aquí podéis más y aquí otro, ¿vale?
Y lo que podéis hacer aquí al recuperar sería así.
De la request, en los parámetros, recupérame ID más y otro.
Y fíjate que el nombre tiene que ser el mismo.
O sea, si aquí le ponemos ID, cuando queramos recuperar esta ID, ese es el nombre.
Si has utilizado Next.js y cosas así, esto te sonará.
Y de hecho, Next.js está utilizando esto por debajo.
Cuando estáis utilizando la estructura de carpetas, con los archivos, el nombre entre corchetes, por debajo Next.js está utilizando esta magia.
Así que es importante el nombre que le ponemos.
Aquí solo nos está interesando la ID.
Entonces, al principio he puesto esto, que pone path to regex.
Te voy a explicar esto porque esto es súper importante también.
Es súper, súper, súper importante.
Y es que, ¿qué pasa?
Que aquí en realidad también podemos poner regex.
Que pudiese capturar las partes de la URL, ¿vale?
Podríamos ponerla directamente igual que se podrían poner un montón de cosas.
Pero, ¿qué pasa?
Que las regex son muy, muy complicadas, muy difíciles.
De hecho, lo puedes hacer, ¿eh?
Puedes hacer así.
Puedes meter aquí la regex y te puedes quedar súper a gusto y lo puedes intentar, ¿vale?
Es un rollo, sobre todo, cuanto más dinámicas son las URLs, más pueden cambiar.
Por suerte, Express usó, usa y popularizó esta biblioteca que se llama path to regex.
Que al final es una biblioteca que han utilizado un montón de bibliotecas en el mundo, como por ejemplo, RealRouter.
A día de hoy ya no la usa porque utiliza su propia solución.
Pero RealRouter y un montón de routers del mundo se basan en path to regex.
Es muy antigua, pero es una idea brillante.
Porque lo que te hace es convertirte path, que son normalmente muy complicados,
te los convierte automáticamente en expresiones regulares para que tú no te tengas que preocupar de esa complejidad.
¿Ves?
Por ejemplo, aquí tendrías este path to regex.
Tú le pasas un path donde le pones aquí los dos puntos bar para que capture este bar y fíjate en qué lo está transformando.
Este sería el regex donde está transformando todo esto.
Claro, no es realista en el que tú estés constantemente haciendo cosas así.
Así que esto por debajo hace esta magia para que nos simplifique como lo vemos, sean mucho más entendibles,
aunque por detrás esté utilizando la magia de los regex.
Pero lo mejor es eso, que no necesitas utilizar regex.
Y puedes hacer cosas muy chulas, como por ejemplo, puedes utilizar aquí ab más cd.
Y este ab más cd, esto lo que va a hacer es decir, vale, pues esto será abcd, abcd, abcd, abcd, bcd.
Esto lo que quiere decir este más es que puede ser la b, puede ser una vez o más, ¿no?
Puedes hacer también, yo que sé, en lugar de esta puedes utilizar e interrogante.
Esto quiere decir que la b puede estar o puede no estar.
Y fíjate que se lee, uy, se lee mucho más fácil que a lo mejor poner una regex que lo podría complicar un poco, ¿vale?
Incluso puedes hacer también, pues aquí, decir que si puede ser una de las dos, ¿vale?
Y esto pues podría ser ab, ¿no?
Porque como es opcional, o abcd, por ejemplo.
Pues aquí lo tendrías.
Ah, bueno, perdón, se me ha olvidado esto, se me ha olvidado esto.
O sea, que es una mezcla entre regex, pero de forma más fácil, ¿no?
Estamos diciendo aquí, oye, este grupo es opcional, entonces funciona con esto y con esto.
Nosotros no vamos a utilizar nada de esto, pero bueno, es solo para que quiero que lo sepas.
Y por supuesto, de nuevo, que muy poca gente lo sabe, pero aquí puedes utilizar regex si quieres.
O sea, podríamos decir todo lo que termina con .dep, ¿no?
Y esto, pues por ejemplo, la barra midudeb, manzdep, manudeb, danideb, todo esto, ¿vale?
Esta ruta funcionaría y con todas estas rutas que terminen así, pues entraría, por ejemplo.
Para que lo sepas, que en Express podéis poner rutas que sean regex.
Eso lo soporta sin ningún tipo de problema.
En este no lo vamos a utilizar, vamos a utilizar el movies con el dos puntos, ¿vale?
Con el segmento que también nos lo transforma en regex para capturar la idea y así ya lo tenemos.
Afecta mucho el performance de la API usar regex en las rutas.
Esto te lo transforma en un regex.
Muchas veces el problema que puede pasar es haber hecho una mala regex.
Si haces una mala regex, entonces sí que es verdad que puedes tener problemas de rendimiento.
Y por eso muchas veces estoy de acuerdo que no recomiendo que hagáis regex manualmente.
Normalmente siempre que podáis utilizar Path to Regex, mejor, ¿eh?
Ya tenemos la idea.
Pues ahora lo que tenemos que hacer es recuperar la película.
Así que ahora hacemos movies.find y de la película movie.id.
Vamos a ver si encontramos la película a través de esa idea, ¿no?
Si tenemos la película, pues nada, la devolvemos.
Jason Movie.
Y si no la tenemos, pues importante lo que vimos el otro día, 404, no se encuentra el recurso.
Y por lo tanto, movie not found, ¿vale?
Le tenemos que informar al usuario que no lo hemos encontrado.
Vamos a probar ahora nuestro endpoint que hemos creado ahora para recuperar una película, ¿vale?
Vamos aquí, recuperar una película.
Send request, ¿vale?
Movie not found porque le he pasado la idea 1.
Y seguramente si miramos aquí, vamos a recuperar la película de Dark Knight, de Batman.
Ahora que tenemos esta idea, send request y ahora ya podemos ver que sí que ha recuperado perfectamente a Bruno Díaz, ¿vale?
Ahora necesitaríamos lo de filtrar por género, ¿no?
En la tercera tenemos que recuperar todas las películas por un género.
Es muy normal que al final nuestros recursos queramos filtrarlos por diferentes cosas.
Puede ser paginación, que eso te lo voy a dejar como ejercicio porque lo veremos más adelante, pero creo que es una cosa que podrías hacer ya perfectamente en JavaScript.
Paginación, puede ser para filtrar por género, por palabra, un montón de cosas.
Entonces, aquí en este caso tenemos un filtro.
Un filtro que nos estamos pasando como una query string.
¿Cómo recuperamos esta query string?
Pues vamos a verlo porque para esto Express es una maravilla.
Como puedes ver, el recurso que estamos utilizando es el mismo que utilizamos para recuperar todas las películas, solo que ahora queremos filtrar por un género en concreto, ¿vale?
Si hacemos un send request, no sé si hay alguna película de terror, igual no lo hay.
Ah, mira, voy a poner aquí esta de sci-fi, vamos a ponerla de action, ¿vale?
Para filtrar por action.
Claro, si ahora utilizamos la request, funcionar funciona, pero fíjate que esta que es de drama no me la ha filtrado, o sea, me la ha dejado ahí.
Lo que vamos a necesitar es modificar nuestro primer endpoint, ¿vale?
De las movies.
¿Qué vamos a hacer aquí?
Vale, pues primero vamos a recuperar el género desde la query.
En la request podemos acceder a la propiedad query y en la query tenemos un objeto donde ya están transformados todos los query params en un objeto.
O sea, que cualquier cosa que le pasemos aquí, por ejemplo, le podemos pasar search y aquí, pues, matrix.
Pues este search ya lo podríamos recuperar aquí, directamente.
Esto es una maravilla, te simplifica un montón la vida, está genial, es de estas cosas que tiene Express como framework de Node, que es que te simplifica la vida, ¿vale?
En este caso solo voy a hacer el de género, pero te invito como ejercicio que tú lo lleves a otro nivel.
Lo que le podemos decir es que si tenemos género, vamos a filtrar por el género.
Y para filtrar por el género, pues podemos hacer un filtered movies, ¿vale?
Donde movies, bueno, movies.filter, ¿vale?
Para cada película, las películas.
Vale, aquí pone esto, aquí pone esto, que movies.filter y tal, pero esto es porque GeekHackoPilot no tiene ni puñetera idea.
No tiene ni idea porque si miramos nuestra API, fijaos que el género es un array, ¿vale?
Por eso muchas veces os digo que tener GeekHackoPilot está bien, pero esto no jauja, ¿vale?
Esto no es, ha, ha, esto no jauja, ¿vale?
No es magia negra.
Y aquí lo podemos ver, ¿no?
Aquí se está equivocando.
Esto no es lo que tenemos que hacer.
De hecho, lo que deberíamos hacer sería más bien filtrar y ver si el movie.genery o gener includes, ¿no?
Si incluye el género que le estamos pasando.
Tendríamos que hacer algo así.
Yo lo voy a hacer un poquito mejor, ¿no?
Esto funcionar funcionaría si le pasamos exactamente, si le pasamos exactamente el filter movies, ¿vale?
Así, si le pasamos exactamente como está escrito, ¿ves?
Este action ahora debería funcionar, ¿vale?
¿Ves? Action, este es action también, action.
Esto ha funcionado, nos ha filtrado esas películas que solo son, o sea, que en el género tienen action, ¿vale?
Antes que teníamos la de drama, pues ya la ha quitado.
Pero ¿qué pasa si pones action en minúscula?
Pues que entonces la hemos liado, ¿ves?
Y no te encuentra nada.
A ver, una cosa que puedes hacer justamente porque muchas veces el lowercase no es importante, o sea, ser case sensitive no es importante en este caso.
Una cosa que puedes hacer aquí es que en lugar de utilizar el punto includes, podríamos utilizar el punto some, ¿vale?
Y decir, vale, exacto, aquí sí que sabe lo que quiero hacer.
Es transformar g.lowercase, ¿vale?
Igual, generate to lowercase, ¿vale?
¿Qué es lo que estamos haciendo aquí?
Pues vamos a asegurarnos que hacemos la comparación de los géneros que tiene la película todo en minúscula.
Y en el filtro también lo vamos a hacer todo en minúscula.
Y así ahora no seríamos case sensitive y por lo tanto se lo podríamos pasar en minúscula y también estaría filtrando.
Se lo podrían pasar todo en mayúscula y seguiría filtrando correctamente, ¿vale?
Esto que estamos viendo, aunque ahora mismo estamos haciendo todos los callbacks y todo esto, lo estamos haciendo dentro, o sea, toda la lógica la estamos dejando dentro de la función, seguramente, hoy no creo, hoy empezaremos con las validaciones.
Y las validaciones sí que las separaremos.
Pero esta lógica la separaremos en la siguiente clase, ¿vale?
Y empezaremos a utilizar algunos patrones de diseño para simplificar esto y poder inyectarles esta lógica.
Y creo que va a ser bastante interesante, así que en la siguiente clase si quieres ver cómo refactorizar esto y utilizar patrones de diseño para poder inyectar de dónde tiene que sacar los datos,
pues lo haremos con base de datos y lo haremos también con este JSON, pues te quedas a la semana que viene que va a estar bastante interesante.
Muy bien, ya tenemos hasta aquí todos los get, pero todavía nos faltaría, claro, o sea, hacer get es lo más típico del mundo.
Vamos con uno más chungo y además así veremos las validaciones.
Vamos a hacer el post, crear una película, ¿vale?
Vamos a crear una película con post y que le podamos pasar toda la información.
Esto tenemos que hacer un post y lo tenemos que hacer en el mismo recurso.
Como puedes ver, siempre, siempre el mismo recurso.
Vale, aquí se ha inventado este JSON, que no sé si tiene mucho sentido, pero lo importante antes de esto es que tenemos que ponerle aquí el content type, el header que tenemos que utilizar.
Así que ponemos application JSON, ¿vale?
Y aquí fíjate que me pone title, matrix, creo que matrix ya está.
Pues vamos a utilizar the good father, perdón, aquí, pa, pa, pa.
Vamos a utilizar esta.
Creo que esta imagen funciona.
Hostia, con el gatillo, que lo está estrangulando el gatillo, Dios mío.
Está estrangulando el gatillo ya.
Vale, a ver qué información tenemos por aquí.
El título, el año, el director, la duración, el post, el género y el rate.
Vale, vamos a hacer que el rate sea opcional.
La idea, obviamente, la vamos a crear.
Hoy te voy a explicar también una cosa bastante importante, que es la diferencia entre post, patch y put.
Lo vas a ver bastante claro, ¿vale?
Post, patch y put.
Vas a ver que mucho más fácil de lo que parece.
Mucha gente se lía, pero lo vas a ver clarísimo.
Lo más importante ahora para empezar con el post es que no tiene una idea.
La idea la vamos a crear nosotros.
Vamos con el post.
Vamos a querer crear esto de aquí, ¿vale?
Vamos a querer crear esto y, por lo tanto, vamos a tener aquí un app.post.
Y aquí vamos a poner barra movies, porque siempre tiene que ser el mismo recurso, ¿vale?
Entonces, el recurso se identifica siempre con la misma URL.
No tenemos aquí un create movie, ¿vale?
Siempre utilizamos el mismo recurso, porque ya lo hemos visto en este pedazo de croquis que os he hecho.
Que cada recurso se identifica con una URL y los verbos definen las operaciones.
Entonces, vamos a hacer el post.
Lo primero que necesitamos es, obviamente, recuperar el title, el year, el director, actos, ¿no?
La duración, el rate, si está, bueno, que no está, porque va a ser opcional.
Y todo esto lo vamos a recuperar de request.body.
Pero, claro, esto lo vimos en la clase anterior y, por lo tanto, no lo voy a volver a explicar completamente, ¿no?
Pero en la clase anterior, que para poder traerte el cuerpo de la request, el request.body, y poder transformarlo,
fíjate lo que tenías que hacer manualmente, ¿no?
Te tenías que escuchar el body y cuando la request iba trayendo data, la tenías que grabar en un string y luego parsearla y tal.
Bueno, por suerte, obviamente, justamente Express tiene un middleware, que también vimos en la clase anterior que significa un middleware,
que lo que hace es capturar esa request y detectar si tiene que hacer esa transformación que nosotros hicimos aquí a mano para entenderla,
para que puedas acceder al request.body directamente y ya tener acceso al objeto que estamos enviando en la request.
Vamos aquí y este request.body, para que funcione, necesitamos utilizar este middleware, ¿vale?
Express.json, express.json.
Es un middleware que, además, ya viene disponible.
Y aquí, entonces, ya podríamos acceder a esta información que vendría enviada por el usuario,
aunque ahora veremos algún problemilla al respecto.
Por ahora, no es importante tanto donde guardamos los datos, así que vamos a mutar el array que tenemos ahí.
Esto no debería, esto no sería, esto no sería rest, porque estamos guardando el estado de la aplicación en memoria.
Así que esto no sería rest, lo terminaremos bien la semana siguiente cuando hagamos todo el tema de base de datos,
pero al menos aquí, para que vayamos entendiendo esto al final, podría ser cualquier cosa
y cuando lo iteremos la semana que viene y lo separaremos, tendremos controladores,
tendremos las rutas totalmente separadas y lo veremos mucho mejor.
Pero aquí, ahora mismo, no es tan importante, así que lo vamos a dejar por aquí, ¿no?
Y aquí podríamos tener el new movie.
Vamos, el new movie.
El new movie, vamos a crear un nuevo objeto, aquí, new movie, donde vamos a tener la ID y para crear la ID,
y esto es súper importante y súper interesante porque no será que no he visto gente que hace cosas muy raras con esto.
Aquí, por suerte, Node.js tiene una biblioteca nativa, que además es parte de la plataforma web, ¿vale?
Que ya te permite crear IDs únicas.
Entonces, puedes traerte cripto, entonces haces node 2.crypto, importante el prefijo, ¿vale?
En este caso ya puedes utilizar cripto.random.uuid y esto te crea un uuid versión 4, ¿vale?
Y ya lo tendrías.
Y esto es totalmente nativo, 0 bytes, sin instalación y ya está.
Y esto además, por si no lo sabías, esto también funciona en el navegador, ¿eh?
Bueno, esto, ahí lo tienes, ¿veis? Funciona en el navegador, que muy poca gente también sabía que esto funcionaba en el navegador.
Un uuid, ¿vale? Es un identificador único universal.
Es universal, unique identifier.
¿Es necesario importarlo? En Node.js es necesario importarlo, ¿vale?
Si no, te peta. Es una pena, pero no sé si algún día cambiará esto, pero en Node.js es necesario importarlo.
Ahora que ya tenemos aquí, pues aquí ahora ya podríamos poner el title, el genre, el director, el year, duración, rate.
Aunque el rate hemos dicho que podría ser opcional.
O sea que el rate podríamos poner rate y si no, vamos a ponerle 0, ¿vale?
Vamos a poner un valor por defecto por si no viene.
Esta nueva película la ponemos aquí y aquí le tenemos que indicar que se ha creado el recurso, que lo ha conseguido crear.
Así que lo que tenemos que decirle no es un 200, sino que sería un 201.
Si tenéis dudas de cuál es el status code, aunque bueno, ya os digo yo que muchas veces los status codes son muy opinables, ¿eh?
El otro día ya vimos este recurso de los gatitos y vais a ver que el correcto para cuando creáis un recurso sería este, 201, que le dice creado, ¿vale?
Y está bastante bien. Aquí en cada uno tenéis una explicación.
Por ejemplo, aquí es una respuesta que indica que la request ha terminado correctamente y se ha creado el recurso.
Este nuevo recurso de descripción puede ser, muchas veces lo que tiene que devolver sería un enlace a ese nuevo recurso,
aunque hay gente que muchas veces lo que hace realmente es devolver el recurso.
Esto depende un poquito de la estrategia que tengas en cuanto a lo que quieras que devuelva.
A veces puede ser interesante devolver el recurso que has creado para actualizar la caché del cliente, por ejemplo, ¿no?
Y así, pues tienes el nuevo ya creado porque este te devuelve la ID.
Y entonces, evitándote crear una nueva request, también tienes la ID porque la ID la hemos creado justamente aquí.
Y a veces es la ID que te crea la base de datos o lo que sea.
Pero lo importante, 201 y aquí tenemos el JSON.
Aunque ahora veremos algún problemilla con esto, ¿eh?
Vamos a poner esto. Aquí tenemos el send request de la película del post.
Hacemos send request, ¿vale?
Se ha creado correctamente.
Me está devolviendo aquí toda la información.
Y por lo tanto, ahora, cuando yo pida todas las películas, deberíamos ver que al final ahora tenemos The Goodfather, ¿vale?
Pero, ¿cuál es el problema de esto que acabo de hacer?
¿Cuál es el problema de esto que acabo de hacer?
A ver si alguien lo sabe.
Exacto. Que no he valido nada, ¿no?
Que no he valido absolutamente nada.
No estoy valido absolutamente nada.
O sea, yo aquí en el title le paso un 1.
En el year le paso pepote.
Y de director le pongo, yo qué sé, le puedo poner lo que me dé la gana, lo que quiera.
De duración le pongo un 0.
Y esto se lo come con unas patatas fritas que, bueno, ¡pam!
Y no solo eso, sino cosas peores todavía.
Porque, además, puedo pasarle mal la información.
O sea, información que es importante, que no se la estoy pasando.
Lo cree así, directamente.
Cosas que están mal, obviamente, ¿no?
Por suerte, estamos al menos, si os fijáis, al menos estamos extrayendo las propiedades.
Pero, como he visto algunas veces, ¿vale?
De hacer algo así.
Hacer algo así.
Que esto ya es como, venga, locurón, locurón.
Rec.body, venga, pa' adentro, todo pa' adentro.
Claro, esto todavía es más peligroso.
O sea, aquí tenemos un montón de cosas muy peligrosas.
Porque en un request.body, aquí ya te puede inyectar lo que te dé la gana.
Esto no se hace nunca, ¿no?
Siempre hay que intentar meter y validar los datos.
Así que, ¿qué es lo que podríamos hacer?
A ver, una cosa muy, muy, muy básica, ¿no?
De primeras.
Obviamente, sería asegurarte que tienes los datos que necesitas.
O sea, realmente, estamos haciendo aquí esto.
Pero, oye, ¿qué pasa si no tengo título?
Vale, pues podríamos hacer esto de, si no tengo título, si no tiene género,
o si no tiene tal, o si no tiene tanto,
pues, oye, un status 400 y un mensaje de que faltan required fields.
¿No? Algo así.
Esto no es lo mejor.
Y menos, claro, ¿qué pasa?
Que si tú intentas hacer este tipo de validaciones así a mano, ¿no?
Dices, ¿y si el año es diferente?
Entonces, el año tiene que ser esto.
¿Y si el rate es diferente?
¿No?
Y si la duración no es un número.
Bueno, ya veis que hacer este tipo de validaciones así es bastante costoso.
¿No? Es un poco rollo.
Esto no lo vamos a hacer así.
Lo que vamos a hacer es utilizar una herramienta muy interesante.
Hay muchas alternativas, ¿vale?
No me empecéis ahora de, ¿por qué no utilizas, yo qué sé, SuperStruck?
¿Por qué no utilizas IO?
¿Por qué no utilizas Jupe?
¿Por qué no utilizas...?
Es que hay mil millones de alternativas.
Diez mil millones de alternativas, ¿vale?
Mil millones.
Tipos no.
Ojo con esto.
Importante.
Lo que vamos a hacer ahora no lo arregla TypeScript, ¿vale?
No lo arregla TypeScript.
Porque hay un error muy común en el que la gente se cree que utilizando TypeScript lo que vamos a hacer ahora se arregla.
Y no es verdad.
Lo que vamos a hacer ahora solo se arregla utilizando algo que se ejecute en Runtime, ¿vale?
Y eso puede ser Zot, puede ser ValiBot, que lo vimos el otro día.
Puede ser Struck, puede ser un montón, todo el que os dé la gana.
Nosotros vamos a utilizar ahora Zot junto con Jupe, uno de los más importantes a día de hoy.
Tampoco es que vamos a ver...
No es un curso de Zot, pero vas a ver que es muy sencillo de utilizar, que para lo que queremos sirve perfectamente.
Y además que como es en el backend, da igual que ocupe un poquito más que ValiBot o que otra.
Para utilizar Zot, lo primero que necesitamos es instalar la dependencia.
Así que nos vamos a clase 3, aquí, npm install Zot y ponemos el menos C, ¿vale?
Porque es la dependencia exacta.
Fíjate que es muy chiquitita y muy rápidamente se instala.
Vamos a traernos de Zeta.json, de Zot, ¿vale?
Y aquí ya teníamos nuestra querida Zeta.
Vale, esta Zeta es a partir de la que vamos a hacer todas las validaciones de los tipos de datos que tenemos.
Aquí hay diferentes estrategias que podríamos hacer.
O sea, podríamos validar la request en lugar de validar el objeto de la AmsMovies.
Pero a mí me parece más interesante crear el esquema de la movie más que preocuparte por la request.
Aunque podrías también crear el esquema del input de la request.
Hay un montón de estrategias, pero por ahora hacemos el esquema y más adelante ya complicaremos esto un poquito.
Porque sobre todo más adelante utilizaremos TypeScript y veremos que puede ser interesante cómo se utiliza TypeScript con Zot.
Pero ahora mismo vamos a enfocarnos en la película, que es lo más importante.
Así que creamos un movie esquema, ¿vale?
Y vamos a representar aquí el objeto de la película.
Así que ahora, ¿qué podemos decir?
Bueno, sabemos que tiene un title, ¿vale?
Así que le decimos que el title es un string.
Y además, lo interesante, cuando hacemos estas validaciones, con esto ya lo tendríamos.
Pero lo interesante es decir, bueno, además me gustaría tener la información de cuál es el error y cambiar el error.
Así que le puedes pasar aquí opciones para que cuando valide y tenga un error, te dé ese error.
Diga, por ejemplo, si el tipo es inválido, imagínate que en el title le pasas un número, pues voy a decir aquí, oye, el movie title must be a string.
No es muy interesante esto, pero hay veces que sí que puede ser importante poner un mensaje personalizado.
También incluso si es requerido, imagínate, pues movie title is required.
O le puedes dar más información, por ejemplo, le puedes decir, please check URL, bla, bla, bla, para no sé qué, no sé cuánto.
Le puedes dar como más contexto.
Más ejemplos, a ver, tenemos el title, el género, mira, el género lo voy a dejar para más adelante porque es un poquito más complicado el ejemplo y para empezar con más sencillos.
El year, fácil.
Z.number, pero ojo, no solo queremos que sea un número.
También una cosa muy interesante de Zot son las validaciones que tiene en cadena.
O sea, que todo se puede encadenar.
Por ejemplo, aquí le decimos Zot, quiero que me valides que es un número, pero claro, un número también puede ser un decimal, por ejemplo, 2,3.
Y en el año queremos un 2,3, no.
Así que vamos a poner punto int.
O sea, también quiero que sea un entero.
Pero claro, si es un entero, también me podrían poner, yo que sé, números negativos.
Bueno, pues le podríamos decir, vale, es un entero y además es un positivo.
O también le podríamos dar un rango de números que son aceptables, ¿ves?
Aquí podemos decirle, oye, como mínimo de 1.900, porque no había películas en 1.800,
y como máximo, pues vamos a poner que como máximo del 2024, ¿vale?
Porque como mucho que sean del año siguiente.
Pero que no haya ningún número que sea fuera de este rango.
Obviamente, cuando ya decimos positivo, si le damos un rango ya no es necesario.
Esto no.
Que sea un entero sí, porque podríamos ponerle 1.900,5 y la liaríamos.
Pero aquí ya estaríamos empezando a validar.
Aquí el número de validaciones, o sea, podríamos estar todo el día, ¿eh?
Director, vamos a poner zString.
La duración, pues un poco lo mismo, ¿no?
Que sea un número, que sea un entero, que como mínimo sea 0.
Más que 0, yo le pondría que sea positivo, ¿no?
Porque poner mínimo 0, básicamente estamos indicando un poquito eso, ¿no?
Tenemos la duración, tendríamos el rate.
El rate, pues lo mismo.
Esto está muy interesante.
Ves que aquí pone int, pero esto no debería ser un int,
porque hemos visto aquí nuestra pseudo base de datos.
Que tenemos 8.5.
Entonces, las puntuaciones van del 0 al 10.
Fíjate que lo bueno es que si lo comparas a como quería yo hacer las validaciones,
es absurdamente fácil.
Tiene cosas tan interesantes como, por ejemplo, el póster.
¿Ves que es una URL?
Claro, muchas veces ver si algo es una URL es un poco rollo, ¿no?
Porque ponemos póster, decimos z.string.
Pero es que también aquí tiene la posibilidad de validar si es una URL.
Así que aquí podrían mirar, pero podrías ir más allá.
Podrías poner validaciones específicas para ver que realmente no solo es una URL,
que termina, por ejemplo, puedes poner el endswith, pues que termine con jpeg,
que termine con una extensión en concreto.
O sea, Zot, la verdad, es una herramienta brutal a la hora de validar no solo formularios,
sino requests de este tipo.
Vamos a poner message, póster, must be a valid URL.
Os voy a enseñar un caso bastante interesante, que es el tema de los enums.
Porque, por ejemplo, ves aquí en géneros que tenemos action, adventure, drama,
y tenemos como diferentes enums.
O sea, porque solo puede...
Hay un número limitado de géneros, no son ilimitados.
Sí que es un array, o sea, podríamos poner género, ya me entendéis.
Podríamos ponerle esto, pero esto no sería correcto del todo,
porque puede ser un número limitado de strings.
No puede ser cualquier string.
Y aquí la gente podría intentar colarnos cosas que no tienen sentido.
Pues una cosa que podemos hacer aquí, por ejemplo, sería poder utilizar un enum.
Podríamos decir un enum, que esto, pues aquí tendríamos el array,
que puede ser action...
Bueno, no sé si encajarán todos.
O sea, mejor me falta alguno.
Bueno, de hecho, creo que sci-fi...
Este lo teníamos por ahí, drama, comedia...
No sé si están todos, porque no lo sé.
Bueno, pues al menos así le decimos, bueno, es un array, pero de esto.
Una forma interesante también de decir que es un array,
no hace falta hacerlo así, como lo he hecho yo.
Lo puedes hacer o no, depende de lo que tú quieras hacer.
Que lo puedes poner al final, ¿vale?
Puedes poner el array al final.
¿Ves aquí a la derecha que he puesto punto array?
Pues sería un poco lo mismo que he hecho, pero al revés.
En este caso en concreto, creo que prefiero ver primero que es un array
y luego que es un enum, pero lo puedes hacer como tú quieras.
Y aunque aquí tengas este parámetro aquí, que sepas que también le puedes poner aquí opciones
para decirle, oye, si es requerido, si es el tipo inválido,
enum, enum, genre, ¿vale?
Lo que sea.
Y con esto ya tendríamos todas las validaciones, ¿vale?
Con esto ya tendríamos todo el esquema de validaciones que queremos hacer de la película.
Obviamente no es correcto hacerlo en cada request, crear aquí el esquema y tal.
Y lo que puede ser interesante es que tengamos una carpeta que le llamamos esquemas, por ejemplo.
Vamos a poner aquí movies.js y aquí podamos sacar tanto la dependencia de Zot, ¿vale?
Vamos a sacar también todo este esquema que hemos creado aquí.
Este esquema.
Y aquí en el esquema, a ver, podéis crear aquí el esquema.
Lo creas una vez, que tiene sentido.
Luego puedes crear una función que sea validate movie,
donde le pasaríamos aquí un object para validar si realmente es un movie.
Y así es como lo validaríamos.
O sea, le pasaríamos el movie esquema punto parse y aquí el objeto.
Aquí hay diferentes métodos que podéis utilizar para validar, ¿no?
Por ejemplo, podéis utilizar el parse.
Aunque a mí, el que más me gusta, sobre todo para este tipo de casos,
para no tener que sea un poco rollo el cómo gestionar el error
y tener que hacer un try-catch, puedes utilizar el save parse.
El save parse lo que hace es devolverte un objeto result que te va a decir
si hay un error o si hay datos.
Y entonces, con un if, pues mucho más simple y mucho más sencillo,
vas a tener la oportunidad de ver si era un error o si no era un error, ¿vale?
Así que yo utilizaría aquel save parse.
Y más adelante, incluso podríamos utilizar el save parse async
para evitar el bloqueo mientras está validando los datos.
Lo importante ahora que tenemos en la función de validate movie,
ya la podríamos utilizar aquí.
Y ahora, en lugar de hacer todo esto que estábamos haciendo,
lo que podríamos hacer es validar el request punto body.
O sea, podríamos decirle, oye, el resultado lo vamos a tener
de validar request punto body.
Y fíjate que vamos a quitar ya todo esto.
Ya no nos tenemos ni que preocupar de si realmente tiene aquí en medio,
si tiene un parámetro y tal.
Lo único que tenemos aquí es el resultado.
Entonces, si el resultado ha tenido un error, pues aquí tenemos que decir,
oye, pues vamos a devolver res status 400,
aunque ahora te explicaré una cosa sobre 400.
JSON, y aquí tendríamos el error y tendríamos el mensaje del error, ¿vale?
Si no ha habido un error, pues podemos continuar con esto
y ya tendríamos toda la información correctamente parseada y validada.
¿Qué quiere decir esto?
Esto quiere decir que aquí sí, aquí sí, si hemos validado correctamente,
aquí sí que podríamos poner el result punto data,
porque no va a dejar pasar datos que no estemos validando.
O sea, si hemos hecho bien la validación, lo que va a pasar es que aquí vamos a tener
todos los datos que hemos validado aquí en el esquema.
Y como le hemos indicado el esquema, vamos a tener todos estos datos.
Y ahora lo voy a saber claramente, porque le voy a intentar enviar datos
que, por lo que sea, no debería pillar, a ver si realmente los pilla y se salta la validación.
Entonces, lo demás lo dejamos igual.
Una cosa que te quiero comentar antes, aquí, esto es subjetivo,
pero también se podría utilizar el 422, ¿vale?
El 422 en lugar del 400.
Normalmente se utiliza el 400 y todo el mundo...
¿Qué es bad request?
Una bad request quiere decir, indica que el cliente ha hecho algo
para que se cometa este error, ya sea que la sintaxis de la request está mal,
que lo que se ha enviado no era correcto del todo, lo que sea, ¿no?
Y está bien, porque esto quiere decir que el cliente no puede repetir esta request
sin hacer una modificación, porque va a tener el mismo problema.
Pero, bueno, hay otra que mucha gente utiliza en este caso,
cuando es una validación, que es unproceable entity, ¿no?
Es el hecho de decir que el servidor ha entendido la request,
el tipo de contenido, que todo funcionaba bien,
pero la sintaxis del recurso que se quería crear no se podía crear
porque había alguna validación, alguna instrucción que no era correcta, ¿vale?
Y también, pues, el mismo warning, ¿no?
El cliente tiene que cambiar algo, porque si lo hace,
pues va a tener el mismo problema.
Entonces, utiliza el que queráis.
Vamos a probar ahora, a ver si envía esto.
Fijaos, title gear, hacemos el request.
Vale, me sale el error un poco raro.
Esto es porque, no sé por qué no está, o sea,
deberíamos parsear el JSON, no sé por qué.
Pero esto, si le ponemos aquí JSON.parse,
lo veremos correctamente.
Y veremos todos los errores que tiene nuestra petición, ¿vale?
Fíjate.
Invalid type.
String, esperaba un string, he recibido un number de title.
Y es que el movie title tiene que ser un string.
Fijaos, lo bien explicado y todo que está, esto es maravilloso.
En un momento hemos hecho validaciones, una validación brutal de todo lo que esperaba
y lo hemos hecho de una forma súper, súper, súper declarativa, súper entendible.
Cualquier persona es capaz de venir aquí y entender las validaciones que está haciendo todo esto.
O sea, no es tan difícil como un if, un if, un if, un if, un if, un if, un if.
Así que es mucho más fácil y así lo que hacemos es decir, bueno, pues ya está.
Si puedes decir, puedes mirar si tienes un error o puedes mirar lo contrario, ¿vale?
El resolve tienes, si es un error, o sea, puedes mirar si es resolve.error o puedes mirar si tienes access, ¿vale?
Y el access, pues es un booleano y puedes decir, bueno, pues si no es access, entonces, o lo puedes mirar al revés.
Si no, si es access y haces lo otro, ¿vale?
Lo que tú, lo que preferáis.
El tema, que como ya tenemos esto, fijaos la maravilla, fijaos la maravilla.
Voy a, voy ahora volver a poner el correcto, ¿no?
Que era este, vamos a poner aquí el correcto, era todo este, ¿vale?
Vale, hay un tema.
Esto no debería funcionar porque el rating no lo hemos hecho opcional.
Así que, ¿vale?
Invalid types, error rating y ojo, ah, el crime.
Es que el crime no lo he puesto como en el enum, pero fijaos lo fácil, ¿no?
¿Ves? Aquí no he puesto crime, así que tenemos que poner aquí el crime, ¿vale?
Vamos a probar otra vez.
Y ahora solo el rate.
Fíjate que me dice que es required.
A ver, una cosa que puedes hacer también, y esto es brutal, ¿no?
Porque a nivel de validación, aquí en el rate también podríais decirle,
oye, pues le voy a poner un valor por defecto y le voy a poner que sea 0 o 5.5, por ejemplo, ¿no?
Le puedes poner valores por defecto, puedes decir que sea opcional,
puedes decir si es nulable, o sea, si se le puede pasar un null.
En este caso, vamos a decirle que por defecto, pues que tenga un valor.
Y por lo tanto, como va a tener un valor por defecto, quiere decir que es opcional.
O sea, que si no nos lo pasan, va a tener este valor, un 5, ¿vale?
Y vamos a ver ahora.
Si hacemos send request, ¿vale?
Ahora se ha creado.
Fíjate, el rate con un 5 y entonces pues ya tenemos.
Pero ahora lo interesante.
¿Qué pasa si alguien me dice SQL y me quiere inyectar aquí select all from users, ¿no?
Algo así, ¿no?
Este SQL, lo quiere inyectar y tal.
Fíjate que, y esto como para backend, esto es algo súper importante.
Y esto es un tema que mucha gente, mucha gente pues como que no, que lo, bah.
Mira, a ver, imagínate esto, ¿no?
SQL, select all from users, ¿no?
¿Habéis visto que no da ningún error?
O sea, no hay ningún problema, no da un fallo, no pasa nada, ¿no?
Y es que vuestras APIs tienen que estar abiertas a todo, tienen que estar abiertas a todo.
O sea, le puedes pasar de todo, pero tienen que ser exquisitas en lo que procesan y tienen que focalizarse en lo que devuelven, ¿vale?
O sea, es un embudo.
Las APIs tienen que ser un embudo.
¿Y por qué se explicó esto?
Porque hay un error muy bestia a nivel de APIs en el que la gente lo que hace es que, yo qué sé, es que claro, ay no, es que me has pasado un SQL, es que a lo mejor, yo qué sé, me has devuelto un array donde no debería no sé qué.
Pues no, lo que tenéis que hacer con las APIs es que las APIs le puedas pasar de todo, de todo y que no reviente.
Porque las APIs tienen que ser robustas, obviamente lo que tienen que hacer luego es procesar lo que necesitan, pero no pueden ser exquisitas en lo que le pasas.
No pueden petar a la mínima de cambio de que si le pasas una cosa, si le pasas no sé qué, lo que sea.
No pueden petar por eso porque es que le has pasado una cosa de más y eso es un error muy común que da bastante rabia además cuando te pasa y te...
¿Por qué? Porque hay veces que a lo mejor al parsear toda la información estás pasando un field más, todo, todo, sí, todo, todo, sí.
Pero a ver, obviamente puede haber pasos en el que, por ejemplo, alguien te está intentando subir una imagen en una request.
Pues obviamente lo que le puedes decir es, oye, o sea, se la puedes pasar y puedes decirle, oye, no acepto esto y le das un status code y tal.
Pero un error muy común es en el hecho de que te pase un objeto, ¿vale? Imagínate esto, ¿no? Que me pasa aquí este SQL.
Y entonces muchas veces te pasa este objeto de SQL y dices, ah, no, es que no me has pasado exactamente y en el orden que esperaba el objeto de la movie.
Y por lo tanto me muero, no respiro, adiós, ¿sabes? Ese es ese tipo de cosas que hay que evitar.
Le estoy pasando el SQL y funciona perfectamente pero simplemente lo ignora.
Lo ignora, ha creado, yo no necesito esto, lo ignoro, punto, ya está, ¿sabes?
Haz lo que te dé la gana pero lo ignoro, ya está. Esto es lo que hay que hacer.
Esto sería la forma en la que puede ser más robusta vuestra API, ¿vale?
Muy bien, entonces ya tenemos el tema de los esquemas.
Hemos separado ya las validaciones. Esto sería un poco como queda el post.
A ver si este es preloquito. Esto sería como ha quedado un post, el post que fijaos que, nada,
la validación separada, si ha ido mal. Aquí, esto sería lo que vamos a hacer luego en base de datos.
Lo haremos en la siguiente clase, ¿vale?
Generamos la ID. Aquí ya tenemos todos los datos validados, así que aquí nos podemos fiar.
O sea, no es lo mismo esto que esto, ¿eh? No es lo mismo para nada.
En uno tenemos todos los datos validados y en el otro no sabemos lo que nos quieren meter.
Y nos pueden estar metiendo de todo. Nunca mejor dicho.
La siguiente es actualizar una película. Y para actualizar una película, normalmente la gente utilizaría el put,
que no está mal, pero yo lo que quiero es actualizar una película, solo una parte de la película.
Por lo tanto, lo que vamos a hacer es utilizar el put, el patch, perdón, y le vamos a poner aquí
HTTP, localhost, 1, 2, 3, 4, movies, y aquí vamos a tener la ID.
Esta no puede ser. Vamos a ver qué película es.
Pues esta, la primera, ¿vale? Me he dado cuenta que el año está mal, 1994, ese no era el correcto.
El correcto era, a ver, content type, tenemos que decir que es application, application JSON, ¿vale?
Y le vamos a decir que lo correcto es que el año en realidad era de 1993, ¿vale?
Obviamente esto ahora mismo no funciona, nos da, nos da, ¿no?
Nos da un 404, no lo encuentra. Venga, pues vamos a hacerlo.
A ver, ¿cuál es el error también muy común que se suele hacer con los patch?
Y ahora os explicaré la diferencia entre put, patch y todo esto.
Venga, patch, obviamente de nuevo tenemos que utilizar, siempre tenemos que utilizar la misma URL, ¿vale?
Es el mismo recurso, ¿vale? Tenemos esto.
A veces, aquí, lo que se haría, un poquito a malas, primero, obviamente, recuperamos la ID, ¿vale?
TheRig.params, luego aquí podríamos buscar la película, ¿no?
Movies.find, he encontrado la película.
Si no encontramos la película, ¿vale? Pues nada, 404, no hemos encontrado la película, vaya rollo, la madre que os parió.
Aquí igual lo mejor sería un findIndex, movieIndex, porque así tendríamos el índice y así lo podemos actualizar.
Eso en este caso, ¿eh? Pero si no, en base de datos lo haríamos de otra forma.
Si el movieIndex es igual a menos uno, esto que no lo hemos encontrado, o menor a cero, ¿vale?
¿Y por qué lo hago así y no hago un find? Pues porque así, en una sola operación, tengo el índice que lo podré utilizar para actualizar
y, además, puedo saber si está o no está.
Si el movieIndex es menos uno, significa que no está esa película con esa ID, 404.
Y aquí, pues, claro, aquí alguien puede decir, si tiene title, movie.title.
O, claro, podemos mutarlo directamente.
Podríamos decirle movie y moviesIndex, ¿no? Y decirle movie.title igualtitle.
Si tiene, y todo esto sacarlo de title, de request.body y así todo el rato, ¿no?
Por ejemplo, la duración.
Pero, claro, fijaos que aquí otra vez tendríamos que hacer las mismas validaciones, en realidad.
Esto no lo hagáis, ¿vale? Esto no se hace.
De hecho, lo que podemos hacer, lo que está chulo, es que como ya tenemos todas las validaciones,
ya tenemos todas las validaciones, las tenemos aquí.
Pero la diferencia de las validaciones que tenemos aquí en MovieSchema es que, claro,
ahora lo que quiero, claro, todas no son requeridas.
Aquí hay diferentes estrategias que podemos hacer.
Depende de lo que podamos pensar que se pueda modificar,
pero vamos a pensar que puede modificarlo todo.
Toda esta información se puede modificar.
Se puede modificar el title, el year, el director, el duration,
pero a lo mejor solo quiere modificar el year, o solo quiere modificar el rate,
o solo quiere modificar el póster, o quiere modificar los tres a la vez.
Pues en ese caso, lo que va a pasar aquí es que en el function vamos a poner un validate partial movie, ¿vale?
Le pasamos un objeto.
Pongo objeto porque en realidad no sabemos si esto es un movie.
Eso está por ver.
Entonces pongo object, o le puedes llamar shape si te molesta esto.
Shape, lo que quieras, ¿vale?
O input, no sé.
Porque hasta que no sepamos si es un movie, vamos a evitar llamarle movie, ¿vale?
Entonces aquí podemos hacer...
¡Ay, joder! Madre mía con el spoiler.
Podemos utilizar el partial.
Y ahora te voy a explicar qué es.
¿Qué es esto de partial?
Esto de partial, si ya sabes TypeScript, seguramente te sonará.
Pero esto de partial, lo que va a hacer es que todos y cada uno de las propiedades que tenemos aquí,
las van a hacer opcionales.
De forma que si no está, pues no pasa nada.
Pero si está, la valida como se supone que la tiene que validar.
Y así lo que estamos haciendo es reaprovechar todo este esquema para la actualización de la película.
Y le decimos, oye, de este esquema, partial.
De forma que si está, perfecto, pero haz que todas las propiedades sean opcionales.
Si no están, pues no pasa nada.
Pero si están, me las validas.
Así hacemos, validate partial movie.
Y utilizando este mismo método, aquí, como hemos hecho con el otro, vamos a, como hemos hecho antes,
¿vale?
Vamos aquí, vamos a poner el result, validate movie, validate movie, reg.body, y ya ahí tendríamos el resultado.
Y ahí, pues ya, si tenemos el error, o al revés, si queréis, voy a utilizar aquí el success para que lo veáis también.
Pues lo mismo, ¿no?
Res status 400.
400, ahí tenemos el error.
Si ha funcionado correctamente, pues mira, esto lo vamos a hacer solo aquí, porque no necesitamos antes.
Vale, movie index, si no encontramos la película, pues nada, 404.
Y ahora sí, lo que podremos hacer es actualizar la película.
O sea, aquí podríamos decirle, y fíjate que aquí, como ya está validado todo, pues es una maravilla.
Porque decimos, update movie, pues la película es todo lo que tenemos en movie index y todo lo que tenemos en result data,
que nos ha pasado nuestro usuario.
Vamos a guardar esta película en el índice, que todo esto es lo que haremos en base de datos en la próxima clase, ¿vale?
Y devolvemos el JSON de la película actualizada.
Así que con esto, ahora ya podemos hacer este tipo de actualizaciones, actualizar una película, ¿vale?
Send request.
Y fíjate, ahora 1993.
Si le digo que el año de esta película es 1998 y send request, ¿ves?
Me actualiza justamente esa película.
Le puedo pasar, le puedo cambiar otra cosa.
Por ejemplo, el title, le puedo decir hola, ¿vale?
Y luego, ahora no es el mejor nombre, pero ¿ves? Ahora tenemos esto.
Y le puedo cambiar el id, le puedo cambiar el id.
Un, dos, tres. A ver, ¿le puedo cambiar el id?
No le puedo cambiar el id.
¿Por qué no le puedo cambiar el id?
¿Por qué no tiene permiso para cambiar el id?
Porque no se está validando, ¿vale?
Y esto es lo interesante de lo que estamos haciendo con esta validación.
Como lo que estamos haciendo es validar todo esto, la id no está.
Ahora es opcional todos los campos que se validan, pero la id no está.
Por lo tanto, aunque tú le pases la id, lo que nos está haciendo Zot es decir, bueno, la id me da igual que me la pases, la voy a ignorar totalmente.
Así que la id, aunque yo se la pase aquí y haga la request, fíjate que no me la modifica, que es justamente lo que esperamos, ¿vale?
Así que es súper importante.
Y esta sería un poquito la forma de que con el mínimo código posible lo que hemos estado haciendo es básicamente decir, ostras, pues ahora ya estamos validando correctamente las cosas y no rompemos nada.
Para que os hagáis una idea, también las validaciones, mira, en este caso alguien me estaba diciendo por aquí, pásale un dato incorrecto.
Por ejemplo, el año, ¿no?
Si tú le pasas aquí un string, 1998, ¿vale? Se lo pasa así, te va a dar un error, ¿ves? Error, tipo inválido, esperaba un número y aquí tienes un string.
Porque lo que estamos haciendo con el partial, con esta validación de aquí, lo que estamos haciendo es, haz que todas las propiedades que hay aquí en el esquema sean opcionales, pero si están las válidas.
Si no están, no pasa nada, no son requeridas. Y además, si no está de ninguna forma la propiedad, la ignoras. Y ya está, ahí lo tendrías.
¿Qué pasa si no le pasas ningún dato? Bueno, si no le pasas ningún dato, seguramente lo que va a hacer aquí en este caso es que lo dejaría exactamente igual, ¿vale?
Lo que va a hacer es no actualizarlo, lo va a dejar exactamente igual. Aquí también podrías hacer que, pues, que le haga algo.
O sea, yo la verdad no creo que pase nada. O sea, no me parece incorrecto el hecho de que tú le pases aquí un objeto vacío y te devuelva lo mismo.
Lo jodido sería que actualizase algo que no debería. Pero lo único que ocurre aquí es que no actualiza nada. Está dejando exactamente lo mismo.
¿Por qué? No hay nada, por lo tanto, no actualiza nada. Ya está. Lo ha actualizado correctamente, pero la actualización no era nada, ¿vale?
Esa sería un poco la idea. Entonces, la diferencia, amigos, y esto es súper, súper importante, diferencia entre post, put y patch.
Yo os voy a decir lo que en teoría es. Primero, quiero que os quede muy claro una palabra que se llama idempotencia, ¿vale?
La idempotencia, y esto es importante que entendáis lo que es la idempotencia, que además en software es bastante importante.
La idempotencia es la propiedad de realizar una acción determinada varias veces y aún así conseguir siempre el mismo resultado.
¿Por qué es importante que entiendas esto de aquí? Porque, claro, es importante saber si tienes funciones que son idempotentes.
En el sentido de que por más que las llames, siempre estás obteniendo el mismo resultado.
Por ejemplo, las funciones que son puras son idempotentes, porque si tú sumas 2 más 2, siempre obtienes el mismo resultado, ¿vale?
Y es lo mismo que si lo hicieses una vez. Pero luego, además, la idempotencia habla también del estado interno que pueden tener las cosas.
Por lo tanto, es importante esto, porque la idempotencia va a ser diferente en estos tres casos.
Porque, por ejemplo, ¿cuál es el propósito del post? El propósito del post es crear un nuevo elemento en el servidor.
Elemento o recurso, ¿vale? Recurso.
Pero el put tiene otro objetivo diferente, ¿no? Que sería actualizar totalmente un elemento ya existente o crear, crearlo, crearlo si no existe.
Y esto es importante porque ya verás que la diferencia es sutil, pero puede ser. O sea, puede crear también el elemento si no existe, ¿vale?
Que es parecido al post, pero tiene una diferencia importante.
Y luego tendríamos aquí el patch, que el patch básicamente es actualizar parcialmente un elemento o recurso, ¿vale? Parcialmente.
Que es justo lo que hemos hecho.
Para que veamos un poco la diferencia, también tenemos la URL, que esto sería barra movies, ¿vale?
Este sería el barra movies, pero ojo porque el put sería barra movies, barra 1, 2, 3, 4, 5, 6, 7, 8, 9, ¿no?
Aquí le pasaríamos la id.
Y aquí en el patch lo mismo, ¿vale?
Diferencia ya importante.
Aunque el post, aunque con el put podrías crear, fíjate que le tendrías que dar tú la id.
Y aquí está un poquito la diferencia, ¿no?
En la semántica, el post, cada vez que realizas una solicitud a una URL con post, estás solicitando crear un nuevo recurso y la URL representa la colección.
En este caso, movies, ¿no?
Y por lo tanto, en la respuesta generalmente te van a dar lo que has creado o la URL donde está lo que has creado, ¿no?
Es idempotente, quiere decir, es la propiedad de realizar una acción determinada varias veces y aún así conseguir siempre el mismo resultado.
Es idempotente post, no es idempotente, no porque creas siempre un nuevo recurso, ¿vale?
Siempre estarías creando un nuevo recurso, por lo tanto, no es idempotente.
Ahora, el put es idempotente, sí que lo es.
El put sí que es idempotente.
¿Por qué?
Porque por más veces que tú hagas la misma solicitud put idéntica a la misma URL, el resultado siempre será el mismo.
¿Por qué va a ser siempre el mismo?
Porque tú le estás indicando aquí la id, porque cuando le vas a pasar los datos y tal, no se está creando otro recurso nuevo.
Si no está, si no existe, sí que se crea, pero se crea con la id y con los datos que le estás pasando.
Pero si vuelve a estar y lo actualizas con exactamente los mismos datos, va a ser exactamente el mismo y vas a obtener siempre el mismo resultado.
En cambio, con post no, porque cada vez que tú llames a post barra movies, aunque siempre le envíes los mismos datos, siempre te va a estar creando un nuevo recurso.
Por lo tanto, diferencia clave entre post y put, ¿vale?
Post no es idempotente y put sí que es idempotente.
Y en patch, en principio sí, pero no está garantizado.
Pero bueno, es un poco más complejado eso.
En principio sí, ¿vale?
Sí, porque si tú siempre le pasa la misma actualización, sí que lo puede ser.
¿Pero qué pasa?
También podría pasar en el put, pero en el patch, ¿qué pasa?
Que normalmente sí lo podría ser y con el put podría pasar algo parecido, lo podría ser, pero depende.
¿Por qué?
Porque a lo mejor tienes un campo updated add, que por lo que sea, cada vez que tú actualizas ese recurso, el updated add ha cambiado.
Bueno, esto en realidad también podría pasar en el put.
Lo que pasa es que no es tan común, ¿vale?
No es tan común porque en el put la idea es más actualizarlo todo y normalmente no es tanto porque quieras actualizar un campo en concreto.
Y por lo tanto, esa información de cuándo se actualizó y tal no suele ser tan vital.
Y en los patches que se van haciendo sí que suelen pasar.
Pero también puede ocurrir el updated add, también puede pasar en el put.
Pero la diferencia está aquí.
El put, crear un nuevo elemento recurso, seguro que no sirve impotente, siempre está creando nuevos recursos.
El put, sí que sirve impotente, aunque como hemos visto, puede ser que no.
Pero la idea es que sí, porque siempre le estás creando el mismo recurso y con los mismos datos y por lo tanto siempre te está devolviendo lo mismo.
Fíjate que en la URL ya le estás pasando la idea.
Y en el patch, lo que quieres es actualizar parcialmente un elemento.
Entonces no es actualizar totalmente, fíjate, totalmente el elemento que ya existe, sino que solo una parte, que justamente es lo que hemos hecho.
Así que esa es la diferencia entre las tres.
Dice sí, pero el updated add sería algo relacionado con la base de datos, tal vez.
Claro, sí, pero aunque quieras o no, si tú devuelves el recurso de la base de datos, imagínate que tú haces un patch.
Imagínate que yo hago esto y le digo que el gear, mira, ves cómo funciona bien, ves, 2022.
Imagínate que yo aquí tengo un campo que es updated add.
Claro, yo le voy donando send request y me va cambiando, me va cambiando eso.
Entonces no sería idempotente como tal.
Se supone que sí que lo es, pero ya te digo que depende.
No se puede decir con 100% de seguridad que siempre el resultado va a ser el mismo.
Independientemente que sea base de datos o que no lo sea, ¿sabes?
No es muy peligroso poder crear la id compute, depende.
Es que, claro, a ver, he dicho lo que se puede hacer, no que se tenga que hacer, ¿sabes?
O sea, ¿es peligroso el crear la id desde fuera?
Pues puede ser que sí, pero muchas veces depende más bien del contexto de vuestras aplicaciones,
no tanto de si está mal o bien per se, ¿entendéis?
Hay veces que puede ser correcto que la id se pueda crear desde fuera porque, por ejemplo,
el identificador sea un identificador que no pueda ser generado,
porque es más interesante que sea ya proporcionado.
Como, por ejemplo, el DNI.
El DNI de un usuario puede ser más interesante utilizar ese identificador,
aunque alguien me dijo, no, es que están repetidos.
Bueno, puede ser, pero hay veces que puede ser más interesante
que ese sea el identificador único del usuario, ¿vale?
Porque es el que identifica al usuario de forma fehaciente
y entonces ya venga de fuera.
Y muchas veces habréis visto que tenéis un formulario de usuario vuestro
donde se actualizan todos los datos, no se parchean.
Tenéis el formulario donde puedes cambiar nombre, apellido, no sé qué, dirección y tal,
y le das, ¡pum!
Y eso lo que hace es un put, porque lo que está haciendo es actualizar todos los datos,
aunque los machaque.
Está enviando todo el objeto.
En cambio, el patch no enviaría todo el objeto, solo enviaría la parte.
Si aquí podríamos estar todo el día, todo el día aquí discutiendo y tal,
sé que esto es objetivamente lo que hacen, ¿vale?
Entonces, es una cosa, esta es la teoría, y en la teoría yo creo que queda bastante claro.
El cómo se hace y cómo se utiliza, que es que podrías hacer,
es que hay un montón de prácticas buenas, malas, ahí fuera,
pero esto, digamos, es la diferencia teórica de los tres.
Que vosotros utilizáis el put como un patch,
que usáis el post para todo, que no sé qué,
eso ya cada uno que haga lo que quiera.
Yo os quería explicar la teoría de la diferencia entre los tres
para que las tengáis claras y podéis seguir utilizando y lo que queráis, ¿vale?
Dicho esto, vamos a hacer una cosa que es importante, el course.
Mirad, amigos, vamos a crear una web aquí mismo, en la clase 3,
rápidamente, ya que tenemos nuestra API REST,
aunque la semana que viene lo haremos en base de datos y tal,
vamos a poner aquí una web, index.html, ¿vale?
Algo, tampoco voy a hacer aquí la web de la vida, ¿vale?
Pero sí que vamos a hacer una web que me ayude como para probar mi API, ¿no?
Probar API REST.
Vamos a tener aquí un main, ¿vale?
Un main y aquí en el title vamos a poner script, type module.
Voy a utilizar type module, más que nada porque así lo puedo poner arriba, ¿vale?
No sé qué pone aquí, aquí pone cosas más raras, pero esto no lo quiero hacer.
Lo que quiero hacer es hacer un HTTP localhost 1, 2, 3, 4, barra movies.
Quiero, básicamente, quiero ver mis películas.
Quiero ver mis películas, he creado mi API, qué bonita es mi API,
la quiero utilizar y vamos a utilizarla, vamos a hacer un fetch y ya está.
Vamos a crear aquí HTML, movies.map y de cada película voy a ir mapeando para tener aquí...
Ah, mira, eso me gustaba.
Un article, ¿vale?
Un article, pa, pa, pa, movie title.
Vamos a poner aquí la ID también porque luego la vamos a necesitar.
Y este map lo vamos a hacer un join.
Fijaos, esto es vanilla JS, ¿eh?
Ni React ni hostias, nada.
Pam, a pelo.
Vale, query selector, main, innerHTML, igual al HTML.
O sea, lo único que estoy haciendo en esta página web es un fetch,
transformar las películas en un poquito de algo article y tal.
De hecho, vamos a poner también la imagen con el source.
Esto es un póster y vamos a ponerle un poquito...
Vamos a poner aquí un style para que no ocupe mucho las imágenes,
que si no, image...
Hostia, a ver el estilo que me hace Jacob Pailo, va.
A ver qué me hace.
Auto, 320 píxeles para que no ocupe mucho.
Max W 100%, vale.
No me ha hecho un estilo de nada, ¿eh?
Bueno, os voy a enseñar una herramienta que yo utilizo un montón
que me encanta, que se llama Servor,
donde tú haces npx, Servor,
y le dices la carpeta donde tiene la página web,
por ejemplo esta, donde son estáticas las páginas web.
Y esto lo que te hace es servirte la página web en una URL
y puedes acceder y verla, ¿vale?
Pero fíjate la página en blanco que me ha dejado esto.
Y fíjate que aquí me ha dado un 404,
como ha dicho, fail to fetch.
Fail to fetch, ¿por qué fail to fetch?
Error que me pone por aquí.
Error course, ¿vale?
El course, el course, ¿vale?
¿Qué está pasando?
Vamos a hablar un poquito del cross origin resource sharing, ¿vale?
El problema por lo que tenemos este error de course.
Lo que pasa con el course es un mecanismo importante
que solo funciona en el navegador.
¿Por qué?
Porque si yo aquí hago un course barra movies,
fíjate que aquí funciona correctamente.
Y entonces dentro, en servidores,
esto es un mecanismo que no funciona.
Es un mecanismo que restringe
si ese recurso lo puedes utilizar en un origen
y es algo que hacen los navegadores.
Entonces, es un mecanismo que te permite
que un recurso sea restringido en una página web
para evitar que un origen o un dominio
fuera de otro dominio,
desde el que se sirvió ese recurso,
pueda acceder.
Entonces, solo funciona en navegadores.
¿Por qué?
Porque los navegadores hacen la petición
y digamos que preguntan a este recurso,
a este origen, ¿no?
Preguntan al localhost 1234.
Fíjate, yo estoy aquí en localhost 8080.
Pero imagínate que esto es páginaweb1.com
y esto es api.pagin2.com, ¿vale?
O sea, da igual que sea localhost o sea lo que sea.
Sería el mismo problema.
Lo que está haciendo el navegador
es preguntarle a la API y decirle,
oye, localhost1234.movies.
Una cosa, es verdad que este dominio,
que no es el tuyo,
que no es el tuyo porque si no,
no te preguntaría si fuese en la misma página,
¿para qué te voy a preguntar?
Seguro que sí.
Pero lo que está pasando es que el navegador
está diciendo, oye, yo estoy en otro dominio
y estoy pidiendo en uno diferente.
Me voy a ver si esto de cruzar estos datos
tiene algún tipo de sentido.
si este dominio que aloja este recurso
realmente tiene o espera
que este dominio de aquí pueda acceder a esos datos, ¿vale?
Y entonces está mirando a ver si puede hacer
esa solicitud real, ¿ok?
Entonces, ¿qué pasa?
Que le ha dicho que no.
¿Y cómo le ha dicho que no?
Pues se lo ha dicho con una falta de headers.
O sea, no ha contestado,
esto lo vimos en una clase,
no hay una cabecera aquí que le diga,
no, no, claro que sí.
Esto está perfecto.
Aquí en las respuestas,
si miramos aquí las respuestas de la cabecera,
no le está dando respuesta.
Le ha preguntado al navegador
y lo que ha dicho nuestra API es,
yo no lo sé, haz lo que te dé la gana.
Y el navegador ha dicho,
pues yo sé lo que voy a hacer,
le voy a decir que no se puede.
Y por eso tenemos aquí el error de course,
que significa cross origin resource sharing,
error de uso compartido de recursos entre dominios.
Y fíjate, aunque se ve muy pequeño,
ves el error que pone missing allow origin header.
O sea, es que falta una cabecera
para realmente decir,
ostras, que sí que puede funcionar esto.
Por lo tanto, si funciona,
si lo único que falta es una cabecera,
¿cómo lo podríamos arreglar?
Nosotros.
Hombre, nosotros tenemos aquí acceso a nuestra API,
porque esto se tiene que arreglar
en la parte del backend,
ya sea en la API,
ya sea en el proxy,
ya sea en el enrutador,
en lo que sea que tenéis,
que pueda añadir esa cabecera.
Porque si no está esa cabecera,
no va a funcionar.
¿Vale?
Así de claro.
¿Quién añade la cabecera?
Eso es lo de menos.
Nosotros, por suerte,
como tenemos acceso aquí al app.js,
nosotros lo podemos añadir aquí.
Y lo que podemos hacer además,
es que según cada endpoint,
nosotros podríamos decir,
vale, solo este endpoint
es el que va a tener acceso.
Así que vamos a poner res.header,
y le decimos access control al labo origin
y le podríamos poner un asterisco.
Y esto funcionaría.
Si le ponemos un asterisco,
lo que estamos diciendo es que
todos los orígenes
que no sean nuestro propio origen,
están permitidos.
Así que, haciendo este cambio,
si volvemos a nuestra página
y refrescamos,
podemos ver que ahora sí,
vale, está en define
porque seguramente estoy accediendo
a una información que no existe.
Vamos a poner gear y ya está.
¿Vale?
Ahora sí, como puedes ver,
sí que tiene acceso,
pero porque no lo ha dicho.
O sea, no se ha dicho,
sí, sí, están todos,
están todos los orígenes
que me pidan información.
Sí, sí.
Y fíjate, aquí lo tienes.
Access control al labo origin,
¿ves?
Asterisco.
Ahora bien,
hay que usar siempre asterisco,
que esto es lo que hace todo el mundo.
Un asterisco y ya está.
De hecho, no veas
cómo se me puso la gente.
¿Es que has dicho asterisco?
Bueno, no hace falta poner asterisco.
Podrías poner aquí directamente
cuál es el origen
al que aceptas que pueda ir.
Por ejemplo,
localhost 8080.
Haciendo esto,
obviamente esto sigue funcionando.
Pero fíjate que ahora,
si vas a Movies,
el access control al labo origin,
aquí hay localhost 8080.
O sea, ya ha cambiado.
Si tú a esto lo cambias a 8081
y refrescamos,
¿vale?
Volvemos a tener el mismo problema.
Porque cuando ha contestado,
la respuesta ha dicho,
access control al labo origin 8081.
Pero es que este dominio es 8080.
Al final piensa que el puerto
es como un origen totalmente distinto.
O sea,
no solo el dominio es importante,
sino que también el puerto.
Y esto,
pues lo mismo sería en página web,
los dominios serán distintos,
¿vale?
Aquí tendríamos esto.
Pero alguien puede decir,
ostras,
claro,
pero yo no sé
cuál va a ser el origen.
Claro,
yo no me puedo saber de antemano
todos los orígenes.
O sea,
yo no puedo saber
si va a ser localhost 3000,
3005,
8000,
no tengo ni idea.
Y es normal que no te lo sepas.
¿Qué es lo que puedes hacer?
A ver,
normalmente lo que se hace mucho
es el hecho de
voy a detectar el origin
y voy a ver qué es lo que hago.
Podríamos tener una lista,
por ejemplo,
de accepted origins.
Tú podrías tener aquí
accepted origins,
pues localhost 8000,
el 1234
y el movies.com
porque obviamente también
vas a querer aquí
los de producción,
movies.com
y también middeb,
pues también tiene acceso
porque me cae bastante bien
este chico
y se la ha ganado.
Pues aquí lo que puedes hacer
es recuperar del origin
la request,
que es una parte
de los headers,
origin.
Aquí tendríamos el header de origin
y aquí simplemente dirías,
oye,
si este origin está
en los aceptados,
pues le añado esto,
¿vale?
Y también hay un caso más,
hay un caso más
que tienes que tener en cuenta
que es bastante importante.
Y este suele ser un error
bastante común,
que el origin,
esta cabecera,
no siempre te la envía
el navegador.
¿Alguien sabe
cuándo no te la envía
el navegador?
Es muy sencillo,
el navegador no envía
nunca el header
de origin
cuando,
cuando la petición
es del mismo origin.
O sea,
si yo estoy en la página
http
localhost
1234
y hago una petición
a localhost
1234
no te envía
justamente
la cabecera
de origin,
¿vale?
Justo para que lo sepáis.
Lo digo porque
muchas veces,
y esto es un error
que me he encontrado a veces,
claro,
la gente hace esto,
accepted origins
includes origin
y pone aquí
el localhost
1234,
pero claro,
hay que tener en cuenta
que si es el mismo origen,
pues tendrías que hacer
algo así,
¿no?
Oye,
y si no tienes origen,
pues a lo mejor
le tienes que dar también.
O también se pueden mirar
otras cabeceras
que te pueden decir
si es el mismo origen,
hay un montón de cabeceras
que te lo pueden decir,
¿vale?
Que lo sepáis
y que lo tengáis en cuenta
que este tipo de cosas
las tienes que tener
porque si no al final
tienes el problema.
¿Por qué no te informa?
Porque no tiene sentido.
No es un course.
Ya no tienes el problema
de access control
a lo origin
porque su propio origen
siempre,
siempre está disponible.
Si no,
imagínate
todos los recursos
que pidieses,
imágenes y tal,
que todos te diesen course
al pedirte a ti mismo.
No tendría sentido,
¿vale?
Así que con esto,
con esto ya lo que podrías hacer
es decir,
bueno,
pues con este
accepted origins y tal,
lo que podemos hacer
es pedir el origin,
¿vale?
Voy a poner aquí
si no tenemos origin,
¿vale?
Y con esto
ya tendríamos
una forma dinámica
de cuando entramos,
fíjate,
ahora,
si es en localhost 8080,
¿ves?
Me está poniendo
exactamente el que necesita.
No hace falta
siempre poner el asterisco.
Ahora bien,
¿qué pasa?
Que esto,
esto funciona,
funciona,
pero no funciona
para todos.
O sea,
hay un caso
bastante interesante.
Mira,
vamos a hacer,
mira,
tengo unos minutos,
vamos a hacer rápidamente
aquí un botón
que sea eliminar,
¿vale?
Y vamos a hacer
que cuando se añada,
vamos a hacer aquí
un document
at evil listener,
voy a hacer el delete
en un momento.
Document
at evil listener,
¿vale?
con el click
esto,
vamos a poner
si la e
target matches button,
entonces
vamos a llamar
a,
vale,
vale,
tiene buena pinta
todo lo que ha hecho aquí.
Lo único que tiene mala pinta
es que me parece
que ha añadido
algo de más.
Esto aquí,
esto aquí,
esto aquí,
esto aquí,
esto aquí,
no,
esto aquí.
A ver,
es que algo está cerrando.
Voy a hacer un momento esto.
Ajá,
este,
ese ahí,
vale.
Bueno,
lo que estoy escuchando
son todos los clics
del documento
y si estoy haciendo click
a un botón,
lo que miro es el artículo
que está más cerca
para recuperar
el ID del dataset,
¿vale?
Y aquí hago un fetch
para borrar justamente
esto de movies
y no sé qué,
no sé cuánto,
¿vale?
Vamos a hacer este delete
en un momento
y vamos a ver otro problema.
Imagínate que esto,
esto lo ponemos
en el delete
que voy a hacer ahora.
Vamos a hacer aquí
el delete,
que también es importante
poder borrar
app delete
barra movies,
¿vale?
Recuperamos la ID,
recuperamos el índice,
hacemos el slice,
ah, bueno,
si no encuentra,
vale,
404 y aquí hacemos
un slice,
splice,
¿vale?
Vamos a hacer el splice
para modificarlo
y quitamos eso
y hacemos el movie deleted,
vale,
perfecto.
Aunque si hacemos un delete,
si hacemos un delete,
no tengo claro
si deberíamos
devolver un
204,
¿puede ser?
Bueno,
da igual,
vamos a dejarlo aquí
con el,
creo que era un 204,
bueno,
pasa nada.
Hacemos el delete,
¿vale?
Para borrar el recurso
y aquí estamos haciendo esto.
Bueno,
si esto ahora lo probamos,
aquí tenemos el delete,
¿veis?
Aquí,
eliminar,
y le doy,
fíjate que este delete
me está dando un problema
de course,
¿vale?
Voy a decir,
bueno,
pues no pasa nada,
me voy aquí a mi app
y hacemos exactamente lo mismo,
¿no?
Hacemos este truquito
de añadir el origen,
el course,
venga,
refrescamos,
le damos aquí,
perfecto,
pim pam,
¿qué ha pasado?
¿Qué ha pasado?
¿Qué ha pasado?
¿Por qué?
Me sigue dando un error,
la madre que lo parió,
que sigue dando un error.
El tema es que el course
es un poco más jodido
dependiendo del método,
¿vale?
Tenemos métodos,
digamos,
métodos,
voy a llamarle normales,
¿vale?
Métodos normales,
que sea get,
get y post
y métodos complejos,
¿vale?
Que serían,
pues todos los demás,
put,
patch y delete.
¿Y qué pasa?
Que en los métodos complejos
existe una cosa
que se llama
course pre-flight.
El course pre-flight,
cuando tú haces una request
utilizando el put,
el patch y el delete,
requiere una petición especial
que se llama options,
¿vale?
Entonces va a hacer
una petición options
que lo que va a hacer
es preguntarle a la API
utilizando el verbo options
y decirle,
oye,
una cosa,
antes de hacer yo
este put
o este patch
o este delete,
cuéntame.
Entonces,
es como una petición previa
que va a hacer
y fijaos aquí,
no sé si lo veis,
pero justo aquí,
justo aquí,
¿veis este options
que está justo
debajo del delete?
¿Qué pasa?
Que este options
es el que le he archivado,
no tiene en ningún sitio
el course.
Por lo tanto,
lo que tenemos que hacer
es decir,
bueno,
pues claro,
tendríamos que poner
app.options
y que cuando
hagamos el movies,
¿no?
Cuando vayamos aquí
al movies,
entonces también añadir
pues todo este tema
de el origin y tal.
Ahora se supone
que en el options
también lo tendríamos,
¿vale?
Aquí la he liado
porque esto es así,
¿vale?
y ahora sí que lo tendríamos,
¿vale?
¡Ay!
Lo he puesto pendiente
porque teníamos que pasar
el response,
claro,
no he hecho
res.send,
¿vale?
Que por eso está fallando,
no he terminado
de enviar la petición,
¿vale?
Ahora no sé
por qué me falla,
res.send,
pasamos 200,
a ver si me falta,
ay,
espérate,
que no sé si me tendré
que ponerle más,
porque ves,
access control,
ahora lo origin,
ah,
porque,
claro,
me faltan,
¿ahora qué pasa?
Claro,
me falta también
pasarle una cabecera
que le indique
cuáles son los métodos
que puede utilizar también,
¿ves?
Allow methods
y entonces le tengo que decir,
oye,
pues puedes utilizar el get,
el post,
el patch,
el delete,
¿vale?
Estos son los métodos
que vas a poder utilizar,
¿vale?
Porque si no,
tampoco puede tener acceso,
no solo es por el origen,
que mucha gente
solo se cree que es el origen,
sino que también,
ay,
pues tampoco,
a ver qué está pasando aquí,
no sé si es que la he liado
con algo,
no sé si es que la estoy liando
con algo,
a ver,
a ver el error que me da,
pues esto en principio
lo estaba haciendo bien,
el options,
no,
pues lo estaba haciendo bien,
el header,
para que luego,
el methods,
lo he escrito bien,
¿no?
Control,
allow methods,
get,
post,
put,
bueno,
el put no hace falta,
esto lo tengo aquí,
ajá,
y el resen,
bueno,
esto también lo he hecho aquí,
que bueno,
esto no importa,
porque esto lo va a enviar aquí,
eh,
alguna cosa la he liado,
¿eh?
Sobra una S,
¿dónde sobra la S?
El access,
¡ay!
¿ves?
¿ves?
¿ves cómo era eso?
Gracias,
gracias,
o sea,
no es un tema de course,
es un tema de dislexia,
gracias,
gracias,
ya decía yo,
pero bueno,
vale,
vamos a ver ahora,
vale,
el preflight,
vale,
ah,
vale,
pues ya,
el delete,
así que lo ha hecho,
sí que lo ha hecho,
vale,
sí que lo ha hecho,
lo que pasa es que el HTML está mal,
aquí,
vale,
ahora sí que lo ha hecho,
porque esto no es access,
esto no devuelvo un JSON,
esto sería res ok,
¿vale?
y cuando tengamos el ok,
entonces lo envía,
ya está,
ya está,
ahora sí,
¿veis?
Ahora lo elimina,
lo elimina,
lo elimina,
o sea que ya está,
con esto lo tendríamos solucionado,
gracias por el typo,
que si no con esto hubiéramos estado ahí todo el día,
el tema es que al final es un tema de cabeceras,
cuando tenéis problemas,
cuando tenéis problemas de course,
no deja de ser esto,
un problema de cabeceras,
que a veces lo puedes hacer en el backend,
perfecto,
que lo puedes hacer en otro sitio,
perfecto,
pero es un tema de cabeceras,
que falta esa cabecera,
entonces esto sería la forma de cómo lo podemos arreglar nosotros,
pero obviamente hay además un middleware que se llama course,
que podéis instalar,
y este course,
¿vale?
lo podéis utilizar aquí,
mira,
podéis hacer app.use barra course,
y aquí,
pues ya tendríais todo solucionado,
pero cuidado con esto,
¿vale?
cuidado con esto,
porque este course,
este middleware,
lo que va a hacer por defecto,
es poneros todo con un asterisco,
que muchas veces,
solucionar,
lo soluciona,
pero el problema que está pasando,
es que le estás diciendo que sí a todo,
y hay veces que a lo mejor no tiene sentido,
entonces,
¿por qué os lo explico?
pues para que entendáis lo que está pasando,
la magia,
no se trata de poner,
simplemente,
course,
y ya está,
lo arregla,
tal,
no,
tenéis que entender qué está pasando,
porque si no,
no lo estáis aprendiendo,
lo que estáis dando palos de ciego,
y os lo ha arreglado,
y bueno,
fantástico que lo ha arreglado,
pero no estáis entendiendo nada,
es verdad que esto lo arregla,
de hecho,
lo podemos ver aquí,
vale,
si yo refresco,
pues salen todas las,
todo,
o sea,
lo arregla todo,
pero fijaos,
que lo que está pasando aquí,
si lo miráis aquí,
os está poniendo un asterisco,
esto es que,
vale,
sí a todo,
esto para vuestros proyectos,
vuestros personales,
puede tener sentido,
pero no,
muchas veces,
pues por ejemplo,
aquí podéis utilizar,
origin,
origin,
callback,
y aquí podríais tener,
el accepted origins,
vale,
al menos para que sepáis,
que hay opciones,
vale,
que no se trata de,
de que sea todo,
sino que esto,
acepta aquí,
unas opciones,
vale,
esto por aquí,
y aquí podríais tener,
pues los accepted origins,
lo podéis sacar de una base de datos,
podéis mirar,
si el origen empieza,
por una cosa,
o lo que sea,
el origin,
esto,
así,
y aquí podríais poner,
esto de accepted origins,
si esto incluye el origen,
entonces tal,
si no tiene el origen,
pues también,
vale,
perfecto,
y si,
y si no,
pues nada,
hay un error,
y al menos con esto,
ya estaríamos volviendo a hacer,
otra vez lo mismo,
veis,
de tener correctamente,
el,
el cost indicado,
con el origen,
que realmente estáis,
estáis utilizando,
vale,
así que es importante,
que esta diferencia,
la sepáis,
y que se puede también configurar,
para llevar esto,
a un nivel un poquito más,
más cuidado.