Conocer y comprender cómo se realizan las conexiones hacia los servidores a través de internet y sus implicaciones en el desarrollo de servidores

1

Bienvenida y presentación del curso

2

Qué es Node y cómo instalarlo

3

¿Qué son y cómo se usan las peticiones HTTP?

4

Métodos, cabeceras y estados

5

Cuerpo y query de la petición

Crear un servidor HTTP en Javascript, y comenzar a escuchar y responder peticiones desde un cliente .

6

Crear un servidor HTTP desde NodeJS

7

¿Cómo pueden venir las peticiones?

8

Recibir información desde el cliente: Body y Query

9

Información contextual: Leer las cabeceras

10

Tipos de respuesta: Vacía, plana, con datos y estructurada

11

Respuestas coherentes

12

Servir archivos estáticos

13

Errores: Cómo presentarlos e implicaciones en la seguridad

Comprender y desarrollar la arquitectura básica de un backend en NodeJS, y comunicarse entre módulos

14

Conceptualmente: Rutas, controladores y bases de datos

15

Rutas y capa de red: Responsabilidades y límites

16

Controladores: Definiendo la lógica de negocio

17

Almacenando la información en una base de datos

Utilizar una base de datos para definir, modelar, almacenar y recuperar la información de nuestra aplicación

18

Tipos de Bases de Datos: Relacionales y No Relacionales

19

Crear y Configurar tu Base de Datos con MongoDB

20

MongoDB: Almacenar y leer datos

21

MongoDB: Actualizar datos

22

MongoDB: Consultar datos

23

MongoDB: Eliminar Datos

24

Gestionar conexiones a la base de datos desde la API

Uso de entidades para crear aplicaciones escalables

25

Escalando la arquitectura: Múltiples entidades

26

Relacionando nuestras entidades

27

Cómo recibir ficheros desde NodeJS

28

Guardar el fichero en el servidor

Conocer el protocolo de websockets, e implementar comunicación cliente/servidor con SocketIO.

29

WebSockets: Qué son, por qué son interesantes y cómo usarlos

30

Manejo de Websockets con NodeJS

31

Conectar la API al servidor de WebSockets

Revisión de lo aprendido, y próximos pasos

32

Revisión y próximos pasos

33

Tips para escalar nuestro proyecto

No tienes acceso a esta clase

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

Cómo recibir ficheros desde NodeJS

27/33
Recursos

En esta clase utilizaremos multer para subir archivos a través de nuestros chats.

Aportes 63

Preguntas 26

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Si te perdiste, pero tienes el código bien.
Borra los mensajes de la base de datos.
Ten creados dos usuarios en la base de datos.
Ahora ve a crear un chat nuevo (POST) y debe ser un body JSON así:

{
	"users": [
		"idDelUser1",
		"idDelUser2"
	]
}

Luego, ve a crear un mensaje (POST), a diferencia de la versión anterior, ahora se de le debe agregar el id del chat correspondiente de la creación que hicimos.

{
	"chat": "idChat",
	"user": "idUser1",
	"message": "mensaje"
}

Ahí puedes crear más mensajes.

Luego para hacer el GET de chat, debes poner el ID del User en la URL:
http://localhost:3000/chat/userId

😃

Al enviar la imagen se guardaba como binario, yo solucione el problema así , obteniendo la extensión del nombre original archivo

const path = require("path")
const multer = require("multer")

const storage = multer.diskStorage({
    destination : "uploads/",
    filename : function (req, file, cb) {
        cb(null, file.fieldname + "-" + Date.now() + 
        path.extname(file.originalname))
    }
})

const upload = multer({ storage: storage });

Por favor, no hagan más en ningún curso esto de meter código y explicarlo por arriba. Hasta la clase anterior todo me funcionaba y hoy me pierdo el día entero tratando de encontrar el error!

Si usan PostMan y les salta error al usar form-data sólo tienen que desactivar el Header de content-type

Guarda la imagen cómo binario, para solucionarlo obtengo la extensión del archivo a cargar.

const multer = require('multer');

const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, 'public/uploads/');
    },
    filename: function (req, file, cb) {
        const [name, extension] = file.originalname.split('.');
        cb(null, `${name}-${Date.now()}.${extension}`)
    }
})

const upload = multer({ storage: storage });
router.post('/', upload.single('file'), function (req, res) {
    controller.addMessage(req.body.chat, req.body.user, req.body.message)
        .then((response) => responses.success(req, res, response))
        .catch((error) => responses.error(req, res, error, 400, 'Error en el controlador'))
});

Qué quilombo se me enredó todo

El profesor se ve que sabe mucho del tema, lo domina, pero tiene una estrategia pedagógica muy deficiente, hay partes del código que escribió pero nunca salen en el video, uno tiene que estar revisando qué partes diferentes de código encuentra y además la clase está muy desordenada, parece que no prepara la clase sino que va escribiendo código sobre la marcha, se nota por los errores que comete.

Nota mental: siempre esperar a que finalice la clase y no empezar a desarrollar sin haber finalizado…

Hay que darse una vuelta por el código, porque ha cambiado más cosas de las que explica en el vídeo, sobre todo en la parte del componente de message.

creo que es interesante saber que tenemos esta hermosa web: https://www.npmjs.com/
para encontrar lo que necesitemos instalar, como utilizarlo, etc … Espero sea de provecho este comentario para la comunidad Platzi.

Para los que fueron a ver el archivo y les parecio algo asi…
b4f00781b05e514e71c37d4c4268fa39

La solucion es esta o al menos mi solucion

const multer = require('multer');
//esto es nativo a si que no necesitas instalarlo
const path = require('path');

const storage = multer.diskStorage({
  destination:  "uploads/",
  filename: (req, file, cb) => {
    cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
  }
})

const upload = multer({ storage: storage })

Si te guarda la imagen… pero como un binario sin extensión. Puedes setear el formato de la imagen de la siguiente forma:
(Windows)

var storage = multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, 'uploads/')
    },
    filename: function (req, file, cb) {
      cb(null, Date.now() + '.jpg') //Appending .jpg
    }
})

const upload = multer({
    storage: storage
})

router.post('/', upload.single('file'), function(req, res){ ...

Muy buena poder ingresar imagenes y documentos desde el multi-part data!!!

Como no podia ver imagenes en mi windows ya que no es tan potente como linux… investige sobre como añadir la extencion y poder tener el archivo correto en mi nodejs.

Les comparto una pagina de stackoverflow donde se explica el procedimiento:

https://stackoverflow.com/questions/31592726/how-to-store-a-file-with-file-extension-with-multer

Tiene muchas funcionalidades para poder hacer cositas entretes viendo el repo donde te indican como debe hacerse paso a paso entiendo todo:

https://github.com/expressjs/multer

Comando para el populate del message teniendo en cuenta el chat y los users dentro dechat`.

export const getMessages = async (filterUser: IMessages) => {
  return new Promise((resolve, reject) => {
    MessageModel.find(filterUser)
      .populate('user')
      .populate({
        path: 'chat',
        populate: {
          path: 'users',
        },
      })
      .exec((error, res) => {
        if (error) {
          return reject(error);
        }
        resolve(res);
      });
  });
};

Modelo de clases
Para entender mejor el desarrollo presento un pequeño modelo de clases de los objetos que se utilizan.

Espero que sea de utilidad

Saludos

Cual es el formato json correcto para enviar mensajes ahora?
Porque esto:

{	
	"user": "5dde5d5629714e036671b618",
	"chat": "5dde70a292162a07820c6bf6",
	"message": "Hola Mundo"
}

Me devuelve:

{
  "error": "Informacion inválida",
  "body": ""
}

Para los que están con la versión de multer 1.4.4

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "./uploads");
  },
  filename: function (req, file, cb) {
    cb(null, file.originalname);
  },
});

const upload = multer({ storage: storage });

Hola!! Por favor nos comparten el código de las clases?

Me podrían orientar cómo se hace en postman el “Multipart Form”. ?.
Gracias

Se complica el código y es necesario estar muy atento. Hay que borrar los datos de la base. Ahora para enviar mensaje primero hay que crear al menos 2 usuarios, luego enviarlos como chat y cuando se tenga el id del chat, se puede enviar el mensaje.

El proyecto no se puede descargar completo o es mi impresión? deja ir viendo lo que uno necesita y no se puede navegar hacía atrás

Hice el codigo en Typescript con async/await. Todo lo hice en el tag database-populate. Les dejo el link:
https://github.com/Aibique-stage1/telegram-backend-js/tree/database-populate


Me voy de este curso hasta que alguien conteste…

Acá dejo solución para que la imagen que suban tenga la extensión y el mismo nombre, para los que estamos cursando este curso en 2021.
La encontré en Medium:
https://medium.com/swlh/how-to-upload-image-using-multer-in-node-js-f3aeffb90657

var storage = multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, './uploads')
    },
    filename: function (req, file, cb) {
      cb(null, file.originalname)
    }
})
var upload = multer({ storage: storage })```

La imagen no debería guardarse en la misma base de datos de mongo?

Bueno para aquellos que seguramente tiene dudas… El profe en ves de filtrar por user, esta filtrando por chat… digamos que cambio la logica esa… Pero como a mi me interesa tambien traer por message por user… cree esto.

network.js

//get message
router.get('/', (req, res) => {
  let filetMessage = {}

  if (req.query.user !== undefined) {
    console.log('soy un user')
    filetMessage = {
      request: req.query.user,
      filter: 'user'
    }
  } else if (req.query.chat !== undefined) {
    console.log('soy un chat')
    console.log(req.query.chat)
    filetMessage = {
      request: req.query.chat,
      filter: 'chat'
    }
  }

  controller.getMessage(filetMessage)
    .then((messageList) => {
      response.success(req, res, messageList, 200)
    })
    .catch((err) => {
      response.error(req, res, 'Unexpected Error', 500, err )
    })
})

controller.js (No hay cambios, si no quieren ponerlo como promesa, es lo mismo)

function getMessage (filetMessage) {
  return new Promise((resolve, reject) => {
    resolve(store.list(filetMessage))
  })
}

store.js

async function getMessage (filterMessage) {
  return new Promise((resolve, reject) => {

      let filter = {} 
      //filetMessage params query ?user=nameUser
      
      if (filterMessage !== {}) {
        if (filterMessage.filter === 'chat') {
          filter = {
            chat: filterMessage.request
          }
        } else if (filterMessage.filter === 'user') {
          filter = {
            user: filterMessage.request
          }
        }
      }
      //se le pasa un parametro para saber que fiktrar
      Model.find(filter)
        .populate('user')
        .exec((err, populated) => {
          if(err) {
            reject(err)
            return false
          }
          resolve(populated)
        })
  })
}

Perdí completamente el hilo.

2 días buscando el problema y todavía no lo encuentro.

El curso venía de 10 hasta que empezó a meter código sin explicar

cuando hago una peticion get de mi chat me dice que data no esta definido, alguna ayuda?

controller.js

const store = require('./store');

function addChat(users){
    if(!users || !Array.isArray(users)){
        return Promise.reject('Invalid user list')
    }
    const chat={
        users: users,
    };
    return store.add(chat); 
}

function listChats(userId){
    return store.list(userId);
}

module.exports = {
    listChats,
    addChat,
}

model.js

const mongoose = require('mongoose');

const Schema = mongoose.Schema;

const mySchema = new Schema({
    users:{
        type: Schema.ObjectId,
        ref: 'user'
    }

}); 

const model = mongoose.model('Chat', mySchema);

module.exports = model;

network.js

const express = require('express');
const router = express.Router();
const response = require('../../Network/responses');
const controller = require('./controller');

router.post('/', function (req, res){
    controller.addChat(req.body.users)
    .then((data)=>{
        response.success(req, res, data, 201);
    })
    .catch(err=>{
        response.error(req, res, 'Internal error', 500, err)
    })
});

router.get('/:userId', function(req, res){
    controller.listChats(req.params.userId)
    .then(users=>{
        response.success(req, res, users, 200);
    })
    .catch(err=>{
        response.error(req, res, data, 500, err);
    })
})

module.exports = router;

store.js

const Model = require('./model');

function addChat(chat){
    const myChat = new Model(chat);
    return myChat.save();   
}

function listChats(usrId){
    return new Promise((resolve, reject)=>{
        let filter = {};
        if (userId){
            filter = {
                users: userId,
            }
        }
        Model.find(filter)
            .populate('users')
            .exec((err, populated)=>{
                if(err){
                    reject(err);
                    return false;
                }
                resolve(populated);
            })
        
    })
}

module.exports = {
    add: addChat,
    list: listChats,
}

Yo revisando mi codigo mil veces porque segun yo al hacer el post de user me regresaba un array vacio, para una hora despues darme cuenta que nunca hice post y estuve haciendo puros get .-.

Mori ajjajaja tendre q analizar mi codigo muy detalladament por q no entendi como es la cuestion de los enlaces en el chat

debiste escribir el codigo y escribirlo ala par que mal

Les dejo el link con información sobre multer

https://www.npmjs.com/package/multer

al día de hoy esto se crea muy diferente, bueno igual la programación es un aprendizaje continuo y constante

Llevo casi una semana intentando encontrar errores en mi codigo por cosas que me faltaron escribir o escribi mal, no me estoy quejando del curso ni nada, es la primera vez que me pasa en todo el curso, pero si es verdad que en esta clase el profe se acelero mucho lo cual por consecuencia hizo que varios nos atrasaramos (por lo que he leido en comentarios), asi que si estas leyendo este comentario y te pasa lo mismo que a mi, revisa que tu codigo este bien escrito, y comparalo a lupa con el que el profe puso en la parte de abajo, hasta el mas pequeño detalle puede hacer que te estanques hasta una semana

Eso si, no pierdas las ganas que si estas aca es porque ya llegaste muy lejos, sigue adelante campeon/a

Al final me sube el archivo sin extension. Luego busco el archivo en la carpeta creada, le agrego la extension “.png” y funciona correctamente.

Para las personas que les guarda el archivo sin la extencion aqui esta la correccion

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "uploads");
  },

  filename: function (req, file, cb) {
    const ext = file.originalname.split(".").pop();
    cb(null, `${file.fieldname}-${Date.now()}.${ext}`);
  },
});

const upload = multer({ storage: storage }); 

Hice un par de mejoras al código para verificar que al momento de crear un chat, todos los usuarios existan en la base de datos.

async function addChat(chat) {
    const allUsersExist = await chat.users.every(async (userId) => {
        // Check userId is a valid Mongo ObjectId
        if (!userId.match(/^[0-9a-fA-F]{24}$/)) {
            return false;
        }

        return await UserModel.exists({ _id: userId });
    });

    if (!allUsersExist) {
        throw new Error('Invalid users');
    }

    const myChat = new Model(chat);

    return await myChat.save();
} 

También cree una función “addMessage” al store del chat, para poder añadir un id al array de “messages”.

async function addMessage(chatId, messageId) {
    if (!chatId || !messageId) {
        throw new Error('Invalid data');
    }

    const chat = await Model.findById(chatId);
    if (!chat) {
        throw new Error('Chat not found');
    }

    const messageExists = await MessageModel.exists({ _id: messageId });
    if (!messageExists) {
        throw new Error('Chat or message not found');
    }

    chat.messages.push(messageId);

    const newChat = await chat.save();

    return newChat;
}  

Finalmente, al momento de hacer un POST a /message, como recibimos el chatId, desde el store.js de message, llamo al store.js de chat para concaternarlo.

async function addMessage(message) {
    if (!message.user || !message.message || !message.chat) {
        throw new Error('Invalid data');
    }
    
    const existsUser = await UserModel.exists({ _id: message.user });
    if (!existsUser) {
        throw new Error('User not found');
    }

    const existsChat = await ChatModel.exists({ _id: message.chat });
    if (!existsChat) {
        throw new Error('Chat not found');
    }

    try {
        const myMessage = new Model(message);

        const newMessage = await (await (await (await myMessage.save()).populate('user'))).populate('chat');

        try {
            await addMessageToChat(newMessage.chat._id, newMessage._id);

            return newMessage;
        } catch (err) {
            await deleteMessage(newMessage._id);

            throw new Error(err);
        }
    } catch (err) {
        throw new Error(err);
    }    
}

Por último agregué un pequeño control porque si un mensaje no se puede agregar a un chat, se elimina.

Esto es brujeria

¡Hola! Si usas POSTMAN y quieres saber como enviar archivos, mira esta página: https://stackoverflow.com/questions/16015548/how-to-send-multipart-form-data-request-using-postman

Que genial es este curso, con lo que llevamos hasta ahora ya tengo forma de pasar mis últimas materias de la universidad 😄

Si cuando hacen el GET de chats les muestra vacío el mensaje, en mi caso es porque debía hacer el return del query en store.js

const getChats = async (userId) => {
    let filter = {};
    if (userId) {
        filter = {
            users: userId,
        }
    }
    try {
        return await Model.find(filter).populate('users').exec();
    } catch (error) {
        throw new Error(error);
    }
}

Por cierto, no estoy usando promesas, estoy trabajando con Async / Await

Les recomiendo apenas termine el video comparar su codigo con el del profesor, ya que en este vide omite algunos pasos y por eso es que al final no siempre funciona algunos detalles del programa

Tuve problema en esta parte cuando lo trabajo desde wls2 en windows 11 (si lo trabajo en el entorno propio de windows 0 problema). El problema es que queda la request de insomia pensando.

Si MongoDB les retorna un error de llave duplicada. Por ejemplo el que a mí me devolvía…

MongoError: E11000 duplicate key error collection: messages_service_nodejs.messages index: user_1 dup key: { user: ObjectId('60b42a2eb3d5f01bc40e32d3') }

Buscando en distintos foros, me dí con dos soluciones:

  • Eliminar la colección donde se encuentra el problema en cuestión ejecutando si se tiene la base de datos en local:
db.collection.drop()

Y en caso de tenerla en Mongo Atlas simplemente se puede hacer en el apartado de collections de forma gráfica.
.

  • En mí caso, eliminar solo la colección problemática no me dió resultados, y debí eliminar la base de datos por completo, específicamente lo que hice fue borrar todas las colecciones y no directamente la BD.
    De forma local se hace:
db.dropDatabase()

pd: Debe seleccionarse la base de datos en cuestión antes de ejecutar cualquier comando en la shell de mongo.
.
En Mongo Atlas, borrar las colecciones una por una o directamente toda la base de datos se hace de forma gráfica facilmente y no voy a extenderme.
.
Espero les sirva!

No sufras, ve el código en Archivos y Enlaces, compara con el tuyo y probablemente encuentres lo que te falta por cambiar.

Alguien me puede decir por qué me da error al incluir “server.use(’/chat’, chat);”?

No entiendo por qué me da error sólo al incluir esa linea, qui´zas sea una estupidez, pero no veo el error.

Gracias a todos.

De está manera podemos hacer que Multer guarde la extensión de los archivos. Simplemente agregamos el modulo interno “path” de node y agregamos la siguiente configuración

var multer = require('multer');
var path = require('path')

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'uploads/')
  },
  filename: function (req, file, cb) {
    cb(null, Date.now() + path.extname(file.originalname)) //Appending extension
  }
})

var upload = multer({ storage: storage });

Ya corregí mi código y quedo igual al de las clases.
Este es el resultado:
en la parte de insomnia no esta completo porque el numero no me lo genera. 😦
Ayuda!!

![](

Mensajes como archivos ayudados con multer. Interesante

termina la parte de integracion de chat e inicia la parte de lectura de ficheros

Están invertidos los videos, creo que este va después del que le sigue…

Aqui tengo una duda, que he estado buscando si quisiera mantener la busqueda en el get de message tanto por el nombre del usuario como por el id del chat como tendria que quedar nuestro controller de getmessages ya intente meterle dos veces el query param para poder filtrar tanto por el chat id y por el name del user y no me sale. 😢

woo que bien, hasta aquí vamos al paso!!

por qué mis fotos se guardan como una especie de binario?

Deben tener cuidado cuando envíen la data como multipart, pues el body llega como: [Object: null prototype].

En todas las clases iba bien hasta que me apareció un error diciendo algo así: module mongoose not found
Luego me dí cuenta que en verdad Mongoose no existía más en mi proyecto!
Hice checkout en GIT a commits anteriors i Mongoose no apareció en el archivo package.json.
No tengo ni idea qué pudo haber ocurrido. Installé de nuevo Mongoose y todo bien.
Pero que raro. Sospecho que fué al instalar Multer.
¿A alguien más le ha ocurrido?

Interesante clase ya sabremos como subir archivos 😃

Yo tuve que poner ‘/:userId?’ porque sino me exigia que en la url hubiera un id ^^

Recibir ficheros

Para quienes les sale el error con la base de datos: response error: MissingSchemaError: Schema hasn’t been registered for model “User”.
Use mongoose.model(name, schema).

En el archivo Store.js de la carpeta messaje aparece la siguiente fucion:

<code> 
async function getMessages(filterChat) {
    return new Promise((resolve, reject) => {
        let filter = {};
        if (filterChat !== null) {
            filter = { chat: filterChat };
        }
        Model.find(filter)
            .populate('user')
            .exec((error, populated) => {
                if (error) {
                    reject(error);
                    return false;
                }

                resolve(populated);
            });
    })
}

Para resolver este error debe cambiar la línea: .populate(‘user’). Por la siguiente:

<code> 
.populate('chat')

Ya con esto podrán utilizar el request:
localhost:3000/message sin errores habiendo hecho todos los otros cambios de este y los otros tres archivos de la misma carpeta que están publicados.

npm i multer

Al subir la imagen no me la sube como jpg o png, alguien sabe a que se debe eso y como puedo solucionarlo?

Hay el mismo ejemplo, pero con MySQL?