No tienes acceso a esta clase

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

No se trata de lo que quieres comprar, sino de quién quieres ser. Invierte en tu educación con el precio especial

Antes: $249

Currency
$209

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

12 Días
6 Hrs
54 Min
25 Seg

Crear, editar y eliminar

15/27
Recursos

Aportes 40

Preguntas 12

Ordenar por:

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

El create quize hacerlo de la siguiente manera, y así créo un producto con las propiedades que quiero 👇… solo por seguridad 😉

create({ name, price, image }) {
  const product = {
    id: faker.datatype.uuid(),
    name,
    price,
    image,
  };
  this.products.push(product);
  return product;
}

Servicio Usuarios

Router Usuarios

Pueden usar el método map en el arreglo de productos para actualizarlos de manera más sencilla y hacerle un filter a los productos cuando vayan a hacer el delete. Les dejo un imagen con un pequeño ejemplo para que vean, ya ustedes pueden mejorarlo si quieren.

Tuve un problema para pasar los datos en el body del request. Estaba recibiendo undefined. Leyendo un poco, encontré que es necesario usar express.json()

Entiendo que es un middleware que se encarga de inyectar el body en el request.

Para usarlo, tienen que agregar la línea

app.use(express.json())

antes de donde inyectan el router en su aplicación

Realmente el codigo ha quedado mas hermoso luego de separar la logica en los distintos servicios

Para mis usuarios cree 3 métodos consultar, crear y eliminar, para crear la data con faker algo que encontré util es ir probando las diferentes opciones que tienen para generar contenido.
Este es mi código para el Servicio de los usuarios:

const faker = require('faker');

class UserService {
  constructor(){
    this.users = [];
    this.generate();
  }
  generate() {
    const limit = 5;
    for (let index = 0; index < limit; index++) {
      this.users.push({
        id: faker.datatype.uuid(),
        name: faker.name.firstName(),
        lastname: faker.name.lastName(),
        email: faker.internet.email(),
      });
    };
  };
  find() {
    return this.users;
  }
  create(data) {
    const newUser = {
      id: faker.datatype.uuid(),
      ...data
    };
    this.users.push(newUser);
    return newUser;
  };
  delete(id) {
    const index = this.users.findIndex(item => item.id === id);
    if (index === -1){
      throw new Error("product not found");
    }
    this.users.splice(index, 1);
    return {id};
  }
}

module.exports = UserService;

Ya superamos la mitad del curso y se me viene haciendo super rápido y ameno!

Agregué algunas mejoras para mantener la lógica de las validaciones fuera de los métodos donde se usan.

Agregué estos dos métodos:

validateIfExist (id) {
  const index = this.users.findIndex(item => item.id === id);
  if (index === -1) {
    throw new Error('User not found');
  }
}

validateIfNotExist (email) {
  const index = this.users.findIndex(item => item.email === email);
  if (index !== -1) {
    throw new Error('User exists');
    console.log(1);
    return false;
  }
}

Y luego los ocupo de la siguiente manera:

1 - Para validar si un usuario existe antes de crearlo usando el correo:

this.validateIfNotExist (email);

2 - Para validar si un usuario existe antes al buscarlo para mostrarlo, editarlo o eliminarlo:

this.validateIfExist (email);

Nota: mi ejemplo lo hice con usuarios a cambio de productos.

categories.router.js

// imports of Modules
const express = require('express');
const CategoriesService = require('../services/categories.service');

// instace of class
const router = express.Router();
const service = new CategoriesService();

// routing
router.get("/", (req, res) => {
  const categories = service.find();
  res.status(200).json(categories);
})


router.get('/:id', (req, res) => {
  const id = req.params.id;
  const category = service.findOne(id);
  if(category){
    res.status(200).json(category);
  } else {
    res.status(404).json({
      message: 'Not Found'
    })
  }
})

router.post('/', (req, res) => {
  const body = req.body;
  const newCategory = service.create(body);
  res.status(201).json(newCategory);
})

router.patch('/:id', (req, res) => {
  const id = req.params.id;
  const body = req.body;
  const updataCategory = service.update(id, body);
  res.status(200).json(updataCategory);
})

router.delete('/:id', (req, res) => {
  const id = req.params.id;
  const deleteCategory = service.delete(id);
  res.status(200).json(deleteCategory);
})

module.exports = router;

categories.service.js

const faker = require('faker');

class CategoriesService {
  constructor(){
    this.categories = new Array();
    this.generate();
  }

  generate () {
    const count = 10;
    for (let i = 0; i < count; i++) {
      this.categories.push(
        {
          id: faker.datatype.uuid(),
          nombre: faker.commerce.department(),
          class: faker.commerce.productAdjective()
        }
      )
    }
  }

  create (data) {
    const newCategory = {
      id: faker.datatype.uuid(),
      ...data
    }
    this.categories.push(newCategory);
    return newCategory;
  }

  find(){
    return this.categories;
  }

  findOne (id) {
    return this.categories.find(item => item.id === id);
  }

  update (id, changes) {
    const index = this.categories.findIndex(item => item.id === id);
    if(index === -1) throw new Error('Ups, Not Found');
    const updataCategory = {
      ...this.categories[index],
      ...changes
    }
    this.categories[index] = updataCategory;
    return updataCategory;
  }

  delete (id) {
    const index = this.categories.findIndex(item => item.id === id);
    if(index === -1) throw new Error('Ups, Not Found');
    this.categories.splice(index, 1);
    return {
      delete: true
    }
  }
}


module.exports = CategoriesService;

Min 1:38

Spread Operator, importantísimo y muy útil para concatenar arrays y objetos

Se repite mucho el código para buscar el index de un elemento del array.
Piensen que tendremos 200 entidades distintas y en TODAS hay que reescribir el MISMO código para actualizar y eliminar.
Les propongo crear un servicio exclusivo para encontrar el index.
Sería algo así:

findTheIndex.js

const findTheIndex = (id, array) => {
  const index = array.findIndex(item => item.id === id)
  if (index === -1) {
    throw new Error('Element not found')
  }
  return index
}

module.exports = findTheIndex

Y lo usamos, por ejemplo, en products:

update(id, changes) {
    const index = findTheIndex(id, this.products)

    const product = this.products[index]
    this.products[index] = {
      ...product,
      ...changes
    }
    return this.products[index]
  }

  delete(id) {
    const index = findTheIndex(id, this.products)
    this.products.splice(index, 1)
    return { id };
  }

Lo probé y sí encuentra los elementos indicados 😄

Increíble curso, hasta ahora de los mejores que he tomado.

Solo me regresaba el precio y ya me había espantado pero no seguí viendo el video jaja

Products_Router:

Products_Service:

Recomendado que en el metodo update() agregar una condicional que no permita cambiar el id:

  update(id, changes) {
    const index = this.products.findIndex(product => product.id === id)
    if (index === -1) {
      throw new Error('Product not found')
    }
    if (changes.id) {
      throw new Error('You cannot update the id')
    }
    this.products[index] = {
      ...this.products[index],
      ...changes
    }
    return this.products[index]
  }

Yo agregaría una intervención para que el patch no modificara el id, ya que no sería una muy buena idea hacer esto en ningún ámbito:

partialUpdate(id, changes){
    const index = this.products.findIndex(item => item.id === id);
    if(index === -1){
      throw new Error('Product not found');
    }
    const product = this.products[index];
    this.products[index] = {
      ...product,
      ...changes,
      id
    };
    return this.products[index];
  }

para el update es mejor usar esta forma

this.products[indexProduct] = { ...product, ...newData }; 

si tu escribes un solo valor pues se van a mantener los otros valores

🚫 Para que el id no se pueda modificar en el update()

this.products[index] = {
      ...product,
      ...changes,
      id: product.id
    }

Así se mande un nuevo id en el body se seguirá manteniendo el id original

Este fue la forma que use para validar la creación del HTTP request POST. En el servicio create( ).
.
Validamos que el tipo de dato sea el correcto en cada uno y si no ingresa un objeto JSON con el siguiente formato

{
"name": "String",
"price": Number,
"image": "String"
}

entonces regresa un mensaje de error.

create(data) {
    if (
      typeof data.name !== 'string' ||
      typeof data.price !== 'number' ||
      typeof data.image !== 'string' ||
      Object.keys(data).length !== 3
    ) {
      return {
        message:
          'Please enter a valid product with the following format, name:string , price:int , image:string'
      };
    }

    const newProduct = {
      // GENERAR NUEVO ID
      id: faker.faker.string.uuid(),
      // OBJETO CON INFORMACIÓN DE NUEVO PRODUCTO ENTREGADO POR EL CLIENTE
      ...data
    };

    // INSERTAMOS EL PRODUCTO AL ARRAY DE PRODUCTOS EN LOCAL STORAGE
    this.products.push(newProduct);

    // REGRESAMOS EL NUEVO PRODUCTO AGREGADO CON SU OBJETO JSON Y SU ID GENERADO.
    return newProduct;
  }

¡Hola, tú!

En clase vimos como eliminar un objeto, no obstante, he visto que en muchos lugares cuando se hace una petición DELETE en realidad lo que hace es cambiar el estado del objeto eliminado para que ya no se muestre más, pero eliminar de una base de datos alguna fila puede llegar a ser una mala practica al final del día, por lo que le hice unas modificaciones, empezando con el objeto de productos, añadiendo un campo state, si está en true, el objeto existe, pero si está en false, el objeto “no existe” en la base de datos

Por lo que dejé el código así con el DELETE, primero la estructura:

  generate() {
    const limit = 5;
    for (let i = 0; i < limit; i++) {
      this.products.push({
        id: faker.datatype.uuid(),
        name: faker.commerce.productName(),
        price: parseInt(faker.commerce.price(), 10),
        image: faker.image.imageUrl(),
        state: true,
      });
    }
  }

Y el DELETE:

  delete(id) {
    const index = this.products.findIndex((item) => item.id === id);
    if (index === -1) return 'Product not found';
    this.products.map((item) => {
      if (item.id === id) {
        item.state = false;
      }
    });
    console.log(this.products);
    return `${id} deleted`;
  }

Tú, si lees esto, te reto a que sigas este mismo manejo de “estados” y me cuentes como dejarías los métodos find y findOne, para que solo muestre los objetos con estado true, ya como final, te invito a que cuando se dé la respuesta al cliente con el find y findOne, no muestre el campo state.

el create quedó asi:

/**
 * POST
 */
router.post('/', ctx => {
  const r = ctx.body;
  const res = {
    message: '[POST] new register',
    data: r
  }

  if (!Array.isArray(r)) {
    ctx.res.status(500).send('post a array')
  } else {
    const newProduct = productsServices.create(res.data);
    ctx.res.status(201).json(newProduct);
  }

  logger.debug('POST', {
    res,
    error: !Array.isArray(r),
  });
})

y el metodo

  create (data) {
    const products = [];

    try {
      data.forEach(element => {
        const id = faker.string.uuid();
        const product = { id, ...element };
        logger.debug('sussefully created', product);

        this.products.push(product);
        products.push(product);
      });
    } catch (error) {
      logger.debug('ERROR', {
        name: error.name,
        message: error.message
      })
    }

    return products
  };

Lo que el profe hace en el delete es utilizar el Spread Syntax, una maravilla.
Aquí la documentación:
https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Operators/Spread_syntax

 const product = this.products[index];
    this.products[index] = {
      ... product,
      ... changes
    }
```;

Esta es mi manera de hacer el update

// ProductsServices

update(id, data) {
        const { name, price, image } = data;
        const product = this.findOne(id);
        product.name = name || product.name;
        product.price = price || product.price;
        product.image = image || product.image;

        return product;
    }

//Product.Routes

router.patch('/:id', (req, res) => {
    const { id } = req.params;
    const body = req.body;
    const product = service.update(id, body);
    res.status(202).json({
        message: 'update',
        product,
    });
});
```js create (data) { const newProduct = { id:faker.string.uuid(), ...data } this.products.push(newProduct) return newProduct } ```create (data) {  const newProduct = {    id:faker.string.uuid(),    ...data  }  *this*.products.push(newProduct)  return newProduct}
![]()```js router.post ('/', (req, res) => { const body = req.body const newProduct = service.create(body) res.status(201).json(newProduct) }) ```
Ayuda, amigos! Por algun motivo no me esta funcionando el metodo post. Cuando envio el request con la data de newProduct simplemente se genera el id pero en el body llega simplemente un objeto vacio. Revize el codigo y esta igual al del profe.

Que les parece esta forma, separar la parte de Producto y un método para actualizar sus props. En updatePr cuando recibo los params hago que por default cada key tenga se auto-referencia por si no viene como param. Así solo cambia lo que viene.

class Product {
  constructor({ name, price, image }) {
    (this.id = faker.datatype.uuid()),
      (this.name = name),
      (this.price = price),
      (this.image = image);
  }

  updatePr({ name = this.name, price = this.price, image = this.image }) {
    this.image = image;
    this.price = price;
    this.name = name;
  }
}

Lo que no me convenció tanto es esta forma jaja (Funciona bien eh)

this.products[index].updatePr(changes);

Pd: Vengo del curso de POO xD, quise separar también en una clase cada producto.

**Update function:** ```js update(id, body){ // Find the index of the product with the provided ID const index = this.products.findIndex(item => item.id === id); // Store the actual product object found at the index const actualProduct = this.products[index]; // Remove the old product at the index and insert an updated product object this.products.splice(index, 1, { id, // Update the name of the product with the new value if provided, otherwise keep the old name name: body.name || actualProduct.name, // Update the price of the product with the new value if provided, otherwise keep the old price price: body.price || actualProduct.price, // Update the image of the product with the new value if provided, otherwise keep the old image image: body.image || actualProduct.image, }); // Return the updated product object return this.products[index]; } ```

create

  create(body){
    const newProduct = {
      id: faker.datatype.uuid(),
      name: body.name,
      price: parseInt(body.price),
      image: body.image,
    }
    this.products.push(newProduct);
    return {
      message: 'created',
      date: this.products.find(item => item.id == newProduct.id)
    }
  }

Explicación del UPDATE del product.service.js

Asi quedo mi services usando typescript

import { ProductsProps } from "./types";

const faker = require("faker");

class ProductsService {
  products: ProductsProps[];
  constructor() {
    this.products = [];
    this.generate();
  }
  generate() {
    const limit = 100;
    for (let index = 0; index < limit; index++) {
      this.products.push({
        id: faker.datatype.uuid(),
        name: faker.commerce.productName(),
        price: parseInt(faker.commerce.price(), 10),
        image: faker.image.imageUrl(),
      });
    }
  }
  create(body: ProductsProps) {
    const newProduct = { ...body, id: faker.datatype.uuid() };
    this.products.push(newProduct);
    return newProduct;
  }
  find() {
    return this.products;
  }

  findById(id: string) {
    return this.products.find((item) => item.id === id);
  }

  update(id: string, newData: ProductsProps) {
    const indexProduct = this.products.findIndex((item) => item.id === id);
    if (indexProduct === -1) throw new Error("product not found");
    const product = this.products[indexProduct];
    this.products[indexProduct] = { ...product, ...newData };
    return this.products[indexProduct];
  }

  delete(id: string) {
    const indexProduct = this.products.findIndex((item) => item.id === id);
    if (indexProduct === -1) throw new Error("product not found");
    this.products.splice(indexProduct, 1);
    return id;
  }
}
export default ProductsService;

Excelente clase

Mi clase de servicio:

Mi controlador o router:

Al crear un nuevo producto yo lo maneje de esta manera. No sé si fue la manera correcta (Soy Front-End)

router.post("/", (req, res) => {

    const body = req.body;

    const { name, price } = body;

    if([name, price].includes(undefined)){

        res.status(400).json({
            "message": "Data undefined",
            body,
        });

    } else {

        const newItem = service.create( body );
        
        res.status(201).json({
            message: "created",
            data: newItem,
        });
    } 
});

El código de la clase con algunas validaciones mas en update y createOne:

ya resolvi mi problema esta es la solucion

function routerApi(app) {
const router = express.Router();
app.use(express.json());
app.use(express.urlencoded({ extends: false }));
// CORS
// Configurar cabeceras y cors
app.use((req, res, next) => {
res.header(‘Access-Control-Allow-Origin’, ‘*’);
res.header(‘Access-Control-Allow-Headers’, ‘Authorization, X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Allow-Request-Method’);
res.header(‘Access-Control-Allow-Methods’, ‘GET, POST, OPTIONS, PUT, DELETE’);
res.header(‘Allow’, ‘GET, POST, OPTIONS, PUT, DELETE’);
next();
});

app.use('/api/v1', router);
router.use('/products', productoRouter);
router.use('/users', usersRouter);
router.use('/categories', cateRouter);

}

const { faker } = require("@faker-js/faker");

class ProductsService {

  constructor(){
    this.products = [];
    this.generate();
  }

  generate(){
    const limit = 100;
    for (let i = 0; i < limit; i++) {
      this.products.push({
        id: faker.datatype.uuid(),
        name: faker.name.fullName(),
        price: parseInt(faker.commerce.price(), 10),
        image: faker.image.imageUrl()
      });
    }
  }

  create(data){
    const newProduct = {
      id: faker.datatype.uuid(),
      ...data
    }
    this.products.push(newProduct);
    return newProduct;
  }

  find(){
    return this.products;
  }

  findOne(id){
    return this.products.find(item => item.id === id);
  }

  update(id, changes){
    const index = this.products.findIndex(item => item.id === id);
    if (index === -1) {
      throw new Error('Product not found');
    }
    const product = this.products[index];
    this.products[index] = {
      ...product,
      ...changes
    };
    return this.products[index];
  }

  delete(id){
    const index = this.products.findIndex(item => item.id === id);
    if (index === -1) {
      throw new Error('Product not found');
    }
    this.products.splice(index, 1);
    return {id};
  }

}

module.exports = ProductsService;

una forma mejor seria solo actualizas lo que necesitas

  update(id, data){
    const product = this.products.find(product => product.id === id);
    Object.assign(product, data);
  }

Explicacion de la logica completa en servicios
importamos el paquete de ‘faker’ para traer información inventada.

const faker = require('faker');

Creamos un constructor que tendrá 2 elementos: Un array vacio (products) donde iran todos nuestros productos generados, y un método (generate) nos dara los parametros (o el envase vacio) para crear nuestros productos.

class ProductsService {
  constructor() {
    this.products = [];
    this.generate();
  }

Nuestro método generate es el que nos creará productos falsos. Comenzamos con nuestra constante limit que será la que usaremos para crear el limite de elementos inventados (limit = 100). La magia sucede dentro del for: cada vez que iteramos, creamos un nuevo elemento con nuestro constructor y lo agregamos al array. Para ello utilizamos el método this.products.push
• this.: lo usamos para llamar al constructor (generate)
• products.: es nuestro array vacio, ahí es donde empujaremos los objetos
• push.: método de array que crea un nuevo indice al final del array y coloca el elemento allí.
A cada atributo de nuestro producto falso hay que instanciarlo con faker. (llamando al método). Los elementos datatype, commerce, image son los elementos que nos da a disposicion faker (dentro tiene otra lista de opciones tales como Price, productName, etc).

generate() {
   const limit = 100;
   for (let index = 0; index < limit; index++) {
     this.products.push({
       id: faker.datatype.uuid(),
       name: faker.commerce.productName(),
       price: parseInt(faker.commerce.price(), 10),
       image: faker.image.imageUrl(),
     });
   }
 }

¡Ya tenemos nuestro objetos creados!
Ahora a por los servicios que les darán utilidad a esos objetos.

  1. El primer servicio será crear los productos con créate(data)(No confundir con nuestro método generate(), con generate lo que hacemos es crear un molde en donde se crearan los productos. Seria como si creáramos el manual completo de instrucción y compráramos los materiales).
    Creamos un objeto (newProduct) que contendrá un id (generado aleatoriamente) y usaremos el spread operator para que acumule cualquier dato que se le agregue (manteniendo los datos anteriores)  aca es donde entra nuestro generador (que tiene 100 moldes con nombres, precios e imagen). Este nos creara objeto por objeto, utilizando el método this (porque estamos iterando sobre los productos que creamos anteriormente). Y devolvemos el producto ya hecho.
create(data) {
   const newProduct = { id: faker.datatype.uuid(), ...data };
   this.products.push(newProduct);
   return newProduct;
 }
  1. Nuestro segundo servicio es de busquedad, este simplemente nos devolverá todos los productos creados.
  find() {
    return this.products;
  }
  1. Este servicio es el que nos identificara un objeto especifico, utilizamos el método find, el cual nos devolverá el objeto, el cual pasemos que sea idéntico al id que escribamos. Por ello el único parámetro que ingresaremos será el id de un item.
findOne(id) {
   return this.products.find((item) => item.id === id);
 }
  1. El siguiente servicio es de actualización, para eso reciclaremos el método anterior, pero a diferencia del anterior, buscaremos por el método findIndex, el cual itera sobre el indice (o el espacio) en el cual se encuentra nuestro objeto.
    Encontrado el indice, crearemos un elemento nuevo sobre el mismo (estaremos actualizando). Luego utilizando nuestro spread Operation diremos que en nuestro objeto estara todo exactamente igual, con los cambios realizados. Finalmente retornamos nuestro producto actualizado:
this.products[index];
  update(id, changes) {
    const index = this.products.findIndex((item) => item.id === id);
    if (index === -1) {
      throw new Error('product not found');
    }
    const product = this.products[index];
    this.products[index] = { ...product, ...changes };
    return this.products[index];
  }
  1. En delete reciclamos el findIndex. (No explique en el anterior, pero al comenzar a generarse nuestros índices a través del 0, si hay un -1, automáticamente es un error).
    Con la lógica de splice (un método que corta) desde index, hasta un elemento adelante (1), lo cortamos. Y devolvemos el id.
  delete(id) {
    const index = this.products.findIndex((item) => item.id === id);
    if (index === -1) {
      throw new Error('product not found');
    }
    this.products.splice(index, 1);
    return { id };
  }
}
module.exports = ProductsService;

excelente clase