Tu primera experiencia con Node.js

1

¿Dónde aprender backend con Node.js actualizado?

2

Todo lo que aprenderás sobre backend con Node.js

3

¿Qué es Node.js?

4

¿Qué es Node.js y para qué sirve?

5

Diferencias entre Node.js y JavaScript

6

Resumen: Diferencias Nodejs y Javascript

7

Instalación de Node.js

8

Arquitectura orientada a eventos

9

Node.js para la web

Manejo y uso de Streams con Node.js

10

Introducción a streams

11

Readable y Writable streams

12

Duplex y Transforms streams

Uso de utilidades de Node.js

13

Sistema operativo y sistema de archivos

14

Administrar directorios y archivos

15

Consola, utilidades y debugging

16

Clusters y procesos hijos

Crea tu primer proyecto en Express.js

17

¿Qué es Express.js y para qué sirve?

18

Creando tu primer servidor con Express.js

19

Request y Response Objects

Aprende a crear un API con REST

20

Anatomía de una API Restful

21

Estructura de una película con Moockaru

22

Implementando un CRUD en Express.js

23

Métodos idempotentes del CRUD

24

Implementando una capa de servicios

Cómo conectarse con librerías externas en Express.js

25

Creación de una BD en MongoAtlas

26

Conexión a MongoAtlas una instancia de MongoDB

27

Conexión con Robot3T y MongoDB Compass a una BD

28

Implementación de las acciones de MongoDB

29

Conexión de nuestros servicios con MongoDB

Conoce como funcionan los Middleware en Express.js

30

¿Qué es un middleware? Capa de manejo de errores usando un middleware

31

Manejo de errores asíncronos y síncronos en Express

32

Capa de validación de datos usando un middleware

33

¿Qué es Joi y Boom?

34

Implementando Boom

35

Implementando Joi

36

Probar la validación de nuestros endpoints

37

Middlewares populares en Express.js

Implementa tests en Node.js

38

Creación de tests para nuestros endpoints

39

Creación de tests para nuestros servicios

40

Creación de tests para nuestras utilidades

41

Agregando un comando para coverage

42

Debugging e inspect

Despliega tu primera aplicación en Express.js

43

Considerando las mejores prácticas para el despliegue

44

Variables de entorno, CORS y HTTPS

45

¿Cómo implementar una capa de manejo de caché?

46

¿Cómo contener tu aplicación en Docker?

47

Despliegue en Now

Conclusiones

48

¿Qué aprendiste en este curso?

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Probar la validación de nuestros endpoints

36/48
Recursos

Aportes 32

Preguntas 4

Ordenar por:

Los aportes, preguntas y respuestas son vitales para aprender en comunidad. Regístrate o inicia sesión para participar.

Para los que les sale el error joi.validate is not a function yo lo solucione cambiando la funcion validate a:

....
const validate = (data, schema) => {
  const { error } = joi.object(schema).validate(data)

  return error
}
....

o tambien pueden bajarle la version de @hapi/joi a la 15.0.3 como se indico en un comentario abajo

La versión 16.1.1 de Joi salió ayer con algunos cambios que rompen el código, por ende es muy probable que las validaciones de datos no te funcionen. Puedes encontrar acá más información al respecto.

Para corregir estos errores sólo debes meter tus objetos de schema que le pasas a la función validate en una función joi.object(). Y llamar el método validate desde el schema, ahora sólo va a recibir la data. Esto va a afectar principalmente tres porciones de código del proyecto, la primera son los schemas que declaras, quedarían así:

const joi = require('@hapi/joi')
const createMovieSchema = joi.object({
    title: movieTitleSchema.required(),
    year: movieYearSchema.required(),
    cover: movieCoverSchema.required(),
    description: movieDescriptionSchema.required(),
    duration: movieDurationSchema.required(),
    contentRating: movieContentRatingSchema.required(),
    source: movieSourceSchema.required(),
    tags: movieTagsSchema
})

La segunda son los métodos de las rutas de movies, quedarían así:

const express = require('express')
const joi = require('@hapi/joi')
const { MovieService } = require('../services')
const {
    movieIdSchema,
    createMovieSchema,
    updateMovieSchema
} = require('../utils/schemas/movies')

const validationHandler = require('../utils/middlewares/validation-handler')

function moviesApi(app) {
    const router = express.Router()
    const movieService = new MovieService()

    app.use('/api/movies', router)

    router.get(
        '/:movieId',
        validationHandler(joi.object({ movieId: movieIdSchema }), 'params'),
        async function(req, res, next) {
            const { movieId } = req.params
            try {
                const movie = await movieService.getMovie({ movieId })
                res.status(200).json({
                    data: movie,
                    message: 'movie by id'
                })
            } catch (error) {
                next(error)
            }
        }
    )
}

module.exports = moviesApi

Y la tercera es el método validate del validation handler que quedaría así:

function validate (data, schema) {
    const { error } = schema.validate(data)
    return error
}

Habiendo hecho estos cambios vas a poder validar tus datos.

O podrías instalar la versión 15.1.0 de @hapi/joi que es la que usa el profesor 😛

Reto cumplido:

Agregue CORS al código usando:

npm i cors

Y siguiendo la documentación apliqué cors:

const express = require('express');
const cors = require('cors');
const app = express();

const { config } = require("./config/index");
const moviesApi = require('./routes/movies');

const { logErrors, wrapErrors, errorHandler } = require('./utils/middleware/errorHandlers');
const notFoundHandler = require('./utils/middleware/notFoundHandler');

// body.parser
app.use(express.json());
app.use(cors());

¿Porqué decidí utilizarlo?
En clases anteriores quise probar la API desde otro proyecto en Vue solamente para poder consumir la API, obtuve un error de CORS, al aplicar este middleware ya pude consumir el proyecto API en mi proyecto Vue:

{
“id”:“11fff70c-c312-4791-b8b4-1a0665edd79e”,
“title”:“Siete minutos (Seven Minutes)”,
“year”:2019,
“cover”:“http://dummyimage.com/800x600.png/5fa2dd/ffffff”,
“description”:“Vestibulum ac est lacinia nisi venenatis tristique. Fusce congue, diam id ornare imperdiet, sapien urna pretium nisl, ut volutpat sapien arcu sed augue. Aliquam erat volutpat.\n\nIn congue. Etiam justo. Etiam pretium iaculis justo.”,
“duration”:62,
“contentRating”:“PG”,
“source”:“http://columbia.edu/eget/orci/vehicula/condimentum/curabitur/in/libero.html”,
“tags”:[“Action|Adventure|Comedy|Drama|War”,“Animation”,“Drama”]
}

Al enviar el SEND en código como dice la clase me trono " TypeError: joi.validate is not a function " y lo solucione con esto:
npm uninstall --save @hapi/joi
npm install --save @hapi/[email protected]

La librería de Joi ya actualizo por lo cuál se requieren algunos cambios en la sintaxis.

La sitnaxis de los schemas es diferente
utils/schemas/movies.js

const createMovieSchema = joi.object({
  title: movieTitleSchema.required(),
  year: movieYearSchema.required(),
  cover: movieCoverSchema.required(),
  description: movieDescriptionSchema.required(),
  duration: movieDurationSchema.required(),
  contentRating: movieContentRatingSchema.required(),
  source: movieSourceSchema.required(),
  tags: movieTagSchema,
})

La forma de hacer la validación igual es de otra forma.
utils/middleware/validationHandler.js

function validate(data, schema) {
  const { error } = schema.validate(data)
  return error;
}

Si alguien más se pregunta por qué su error stack no se ve igual que el de @glrodasz

es por que por defecto el stack está desactivado ahora. Ahora hay que hacer:

  const { error } = schema.validate(data, { errors: { stack: true } })
{
  "title": "Notti bianche, Le (White Nights)",
  "year": 2019,
  "cover": "http://dummyimage.com/800x600.png/ff4444/ffffff",
  "description":
    "In hac habitasse platea dictumst. Etiam faucibus cursus urna. Ut tellus.",
  "duration": 66,
  "contentRating": "G",
  "source": "https://ovh.net/semper/rutrum/nulla/nunc.jsp",
  "tags": [
    "Action|Adventure",
    "Action|Adventure|Thriller",
    "Horror|Western",
    "Horror|Thriller",
    "Comedy|Romance|Sci-Fi",
    "Adventure|Animation|Children|Comedy|Fantasy",
    "Drama"
  ]
}

Fecha 28/julio/2020

Para los que tienen problemas y no les valida los datos JOI cambio algunas cosas y la forma en la que validamos los datos la cambie también porque no me validaba nada aquí dejo del código espero le sirva a alguno

Mi capa de schema se le agrega el joi.object({ Aquí adentro va el schema })
No se lo agregue a movieIdSchema , ya que se la capa en la parte de rutas

const joi = require('@hapi/joi');

const movieIdSchema = joi.string().regex(/^[0-9a-fA-F]{24}$/)
const movieTitleSchema = joi.string().max(80)
const movieYearSchema = joi.number().min(1888).max(2077)
const movieSchemaCover = joi.string().uri()
const movieDescriotionSchema = joi.string().max(300)
const movieDurationSchema = joi.string().min(1).max(300)
const movieSourceSchema = joi.string().uri()


const createMovieSchema = joi.object({
    title: movieTitleSchema.required(),
    year: movieYearSchema.required(),
    cover: movieSchemaCover.required(),
    description: movieDescriotionSchema.required(),
    duration: movieDurationSchema.required(),
    source: movieSourceSchema.required()
})


const updateMovieSchema = joi.object({
    title: movieTitleSchema,
    year: movieYearSchema,
    cover: movieSchemaCover,
    description: movieDescriotionSchema,
    duration: movieDurationSchema,
    source: movieSourceSchema
})

module.exports = {
    movieIdSchema,
    createMovieSchema,
    updateMovieSchema,
};

Mi capa de rutas
Aquí agregue el joi.object({}) para movieIdSchema eso para cada vez que se quiera validar el ID
el resto sigue igual dejo un ejemplo de como queda el resto abajo y recuerden requerir joi para poder usar el metodo .object()

router.get('/:movieId',  validationHandler(joi.object({ movieId: movieIdSchema }), 'params'), async (req, res, next) => {...

//Aqui pueden ver que se mantiene normal el resto igualmente recuerden requerir validationHandler
router.post('/', validationHandler(createMovieSchema), async (req, res, next) => {...

Mi capa de validación o validationHandler
ahora retorno de modo asyncrono cambie check por data el resto es entendible si hay alguna otra duda comentarlo, yo lo hice de esta forma, ya que se me hizo más comprensible

const boom = require('@hapi/boom')

function validationHandler(schema, data = 'body'){
  return async (req,res,next) =>{
    try {
      await schema.validateAsync(req[data]);
      next();
    } catch (err) {
      next(boom.badRequest(err))
    }
  }
}


module.exports = {
  validationHandler
};

Esta es mi corrección del codigo ya que no era un script() sino un number().

Reto:

const express = require('express');
const app = express();

const bodyParser = require('body-parser');

const { config } = require('./config/index');
const moviesApi = require('./routes/movies');
const notFoundHandler = require('./utils/middleware/notFoundHandler');

const {
    logErrors,
    wrapErrors,
    errorHandlers
} = require('./utils/middleware/errorHandlers');

**// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());**

// Se agrega middleware de body-parser
//app.use(express.json());

// routes
moviesApi(app);

// Catch 404
app.use(notFoundHandler);

app.use(logErrors);
app.use(wrapErrors);
app.use(errorHandlers);

app.listen(config.port, function() {
    console.log(`Listening in http://localhost:${config.port}`);
});

Para las personas que se les este presentando el problema en postman: "message": "\"title\" is not allowed"
  
Remuevan las llaves de los validationHandlers en los metodos .post y .put en el archivo routes/movies.js.
  
Antes del cambio:

router.post('/', validationHandlers({createMovieSchema}), async function(req, res, next){

Despues del cambio:

router.post('/', validationHandlers(createMovieSchema), async function(req, res, next){

Espero que les sea de ayuda.

Otra forma de resolver el problema joi.validate este caso para la versión joi ^17.1.1, gracias a los comentarios de abajo mas investigando un poco hice el siguiente refactor

schema/movies.js

const joi = require('@hapi/joi');

const movieIdSchema = joi.string().regex(/^[0-9a-fA-F]{24}$/);
const movieTitleSchema = joi.string().max(80);
const movieYearSchema = joi.number().min(1888).max(2077);
const movieCoverSchema = joi.string().uri();
const movieDescriptionSchema = joi.string().max(300);
const movieDurationSchema = joi.string().min(1).max(300);
const movieContentRatingSchema = joi.string().max(5);
const movieSourceSchema = joi.string().uri();
const movieTagsSchema = joi.array().items(joi.string().max(50));

const createMovieSchema = joi.object({
    title: movieTitleSchema.required(),
    year: movieYearSchema.required(),
    cover: movieCoverSchema.required(),
    description: movieDescriptionSchema.required(),
    duration: movieDurationSchema.required(),
    contentRating: movieContentRatingSchema.required(),
    source: movieSourceSchema.required(),
    tags: movieTagsSchema
});

const updateMovieSchema = joi.object({
    title: movieTitleSchema,
    year: movieYearSchema,
    cover: movieCoverSchema,
    description: movieDescriptionSchema,
    duration: movieDurationSchema,
    contentRating: movieContentRatingSchema,
    source: movieSourceSchema,
    tags: movieTagsSchema
});

module.exports = {
    movieIdSchema,
    createMovieSchema,
    updateMovieSchema
}
const boom = require('@hapi/boom');

const validate = (data, schema) => {
    const { error } = schema.validate(data);
    return error;
}

const validationHandler = (schema, check = 'body') => {
    return (request, response, next) => {
        const error = validate(request[check], schema);
        error ? next(boom.badRequest(error)) : next();
    };
}

module.exports = validationHandler;

Fuente: github

Tengo el siguiente error

Error: Object schema must be a valid object
    at new module.exports (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/node_modules/@hapi/hoek/lib/error.js:23:19)
    at module.exports (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/node_modules/@hapi/hoek/lib/assert.js:20:11)
    at internals.Base.method [as keys] (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/node_modules/@hapi/joi/lib/types/keys.js:241:17)
    at Object.args (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/node_modules/@hapi/joi/lib/types/keys.js:48:23)
    at Object.internals.generate (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/node_modules/@hapi/joi/lib/index.js:259:31)
    at Object.root.<computed> [as object] (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/node_modules/@hapi/joi/lib/index.js:58:30)
    at validate (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/utils/middleware/validationHandler.js:12:27)
    at /Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/utils/middleware/validationHandler.js:18:23
    at Layer.handle [as handle_request] (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/node_modules/express/lib/router/layer.js:95:5)
    at next (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/node_modules/express/lib/router/route.js:137:13)
Error: Object schema must be a valid object
    at new module.exports (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/node_modules/@hapi/hoek/lib/error.js:23:19)
    at module.exports (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/node_modules/@hapi/hoek/lib/assert.js:20:11)
    at internals.Base.method [as keys] (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/node_modules/@hapi/joi/lib/types/keys.js:241:17)
    at Object.args (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/node_modules/@hapi/joi/lib/types/keys.js:48:23)
    at Object.internals.generate (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/node_modules/@hapi/joi/lib/index.js:259:31)
    at Object.root.<computed> [as object] (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/node_modules/@hapi/joi/lib/index.js:58:30)
    at validate (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/utils/middleware/validationHandler.js:12:27)
    at /Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/utils/middleware/validationHandler.js:18:23
    at Layer.handle [as handle_request] (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/node_modules/express/lib/router/layer.js:95:5)
    at next (/Applications/XAMPP/xamppfiles/htdocs/platzi master/backend-con-nodejs/movies-api/node_modules/express/lib/router/route.js:137:13)

Mi Código

const boom = require('@hapi/boom');
const joi = require('@hapi/joi');

function validate(data, schema) {
    //console.log(schema);
    const { error } = joi.object(schema).validate(data);
    return error;
}

function validationHandler(schema, check = 'body') {
    return function (req, res, next) {
        const error = validate(req[check], schema);
        error ? next(boom.badRequest(error)) : next();
    }
}

module.exports = validationHandler;

¿A alguien más le aparece este error?

Chicos para el error de validación con Joi, lo único que tiene que modificar es :
Con la versión 17.1.1:

function validate(data, schema) {
  const { error } = joi
    .object(schema)
    .validate(data, { errors: { stack: true } });
  return error;
}

Cualquier duda me escriben

Para los que tengan el error de “joi.validate is not a function”, deben cambiar lo siguiente en el archivo validationHandlers.js:

function validate(data, schema) {
  const { error } = joi.object(schema).validate(data)
  return error;
}
{
    "title": "Notti bianche, Le (White Nights)",
    "year": 2019,
    "cover": "https://dummyimage.com/800x600.png/ff4444/ffffff",
    "description": "In hac habitasse platea dictumst. Etiam faucibus cursus urna. Ut tellus.",
    "duration": 66,
    "contentRating": "G",
    "source": "https://ovh.net/semper/rutrum/nulla/nunc.jsp",
    "tags": [
		"Action|Adventure",
		"Action|Adventure|Thriller",
		"Horror|Western",
		"Horror|Thriller",
		"Comedy|Romance|Sci-Fi",
		"Adventure|Animation|Children|Comedy|Fantasy",
		"Drama"
	  ]
}

Hola me paso el mismo error al intentar hacer el POST de una movie,

joi.validate is not a function

Viendo las soluciones recomiendo la que han indicado de usar la misma versión para Joi del proyecto @hapi/[email protected], creo que esto es normal y en proyecto reales tampoco es obligatorio hacer un refactor cada vez que se actualiza la libreria

Para los que tengan el error de validación, lo solucione así, pasé de este código en validationHanlder

const boom = require(’@hapi/boom’);
const joi = require(’@hapi/joi’);

const validate = (data, schema) => {
const { error } = joi.object(schema.validate(data);
return error
}

function validationHandler(schema, check = ‘body’) {
return function (req, res, next) {
const error = validate(req[check], schema);
error ? next(boom.badRequest(error)) : next();
}
}

module.exports = validationHandler;

A este, no coloque el join.object sino se valida directamente el schema

const boom = require(’@hapi/boom’);

const validate = (data, schema) => {
const { error } = schema.validate(data);
return error
}

function validationHandler(schema, check = ‘body’) {
return function (req, res, next) {
const error = validate(req[check], schema);
error ? next(boom.badRequest(error)) : next();
}
}

module.exports = validationHandler;

{
“title”: “Notti bianche, Le (White Nights)”,
“year”: 2019,
“cover”: “https://dummyimage.com/800x600.png/ff4444/ffffff”,
“description”:
“In hac habitasse platea dictumst. Etiam faucibus cursus urna. Ut tellus.”,
“duration”: 66,
“contentRating”: “G”,
“source”: “https://ovh.net/semper/rutrum/nulla/nunc.jsp”,
“tags”: [
“Action|Adventure”,
“Action|Adventure|Thriller”,
“Horror|Western”,
“Horror|Thriller”,
“Comedy|Romance|Sci-Fi”,
“Adventure|Animation|Children|Comedy|Fantasy”,
“Drama”
]
}

la diferencia es que haciendolo como dice Dante, no aplica la validacion al menos no en el POST crea la pelicula sin la validacion, solo colocando el titulo pasa

No hay alguna forma de que regrese todas las validaciones de una vez y no una por una a medida que se van corrigiendo ?

Anteriormente había usado Body Parser y lo implementaba de la siguiente manera:

Lo requerimos

const bodyParser = require('body-parser');

y la implementación sería:

// body parser
app.use(bodyParser.urlencoded({
    extended: false
}));

Luego en lugar de usar:

// body parser
app.use(express.json());

sería

// body parser
app.use(bodyParser.json());

y siempre me funcionó bien

Actualice mi codigo con el joi.object y ahora funciona la validacion pero lo unico que falta que me salga el mensaje y stack como en la clase.

Si a alguien le llega a pasar un error luego de las sugerencias de los compañeros, no se olviden de seleccionar JSON al enviarlo en POSTMAN.

no entiendo algo supuestamente se hacen validaciones de numeros y eso pero se meten strings en estos campos y no validad nada… estoy algo aburrido porque uno intenta aprender algo, pero antes queda mas confundido de lo que estaba

Compañeros a alguien si le valida que sean números y no strings? la verdad llevo días intentado solucionar eso y no me da, alguien le funciona bien y me puede colaborar…

El sitio de express.js nos da esta lista con los middlewares que son constantemente mantenidos por el Express.js team
https://expressjs.com/en/resources/middleware.htmlhttps://expressjs.com/en/resources/middleware.html

Interesante… y la lectura esta en la siguiente clase o donde?

😄