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:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

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:

{
鈥渋d鈥:鈥11fff70c-c312-4791-b8b4-1a0665edd79e鈥,
鈥渢itle鈥:鈥淪iete minutos (Seven Minutes)鈥,
鈥測ear鈥:2019,
鈥渃over鈥:鈥http://dummyimage.com/800x600.png/5fa2dd/ffffff鈥,
鈥渄escription鈥:鈥淰estibulum 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.鈥,
鈥渄uration鈥:62,
鈥渃ontentRating鈥:鈥淧G鈥,
鈥渟ource鈥:鈥http://columbia.edu/eget/orci/vehicula/condimentum/curabitur/in/libero.html鈥,
鈥渢ags鈥:[鈥淎ction|Adventure|Comedy|Drama|War鈥,鈥淎nimation鈥,鈥淒rama鈥漖
}

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 鈥渏oi.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 = 鈥榖ody鈥) {
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 = 鈥榖ody鈥) {
return function (req, res, next) {
const error = validate(req[check], schema);
error ? next(boom.badRequest(error)) : next();
}
}

module.exports = validationHandler;

{
鈥渢itle鈥: 鈥淣otti bianche, Le (White Nights)鈥,
鈥測ear鈥: 2019,
鈥渃over鈥: 鈥https://dummyimage.com/800x600.png/ff4444/ffffff鈥,
鈥渄escription鈥:
鈥淚n hac habitasse platea dictumst. Etiam faucibus cursus urna. Ut tellus.鈥,
鈥渄uration鈥: 66,
鈥渃ontentRating鈥: 鈥淕鈥,
鈥渟ource鈥: 鈥https://ovh.net/semper/rutrum/nulla/nunc.jsp鈥,
鈥渢ags鈥: [
鈥淎ction|Adventure鈥,
鈥淎ction|Adventure|Thriller鈥,
鈥淗orror|Western鈥,
鈥淗orror|Thriller鈥,
鈥淐omedy|Romance|Sci-Fi鈥,
鈥淎dventure|Animation|Children|Comedy|Fantasy鈥,
鈥淒rama鈥
]
}

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?

馃槃