No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Crear, editar y eliminar

15/27
Recursos

Aportes 34

Preguntas 11

Ordenar por:

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

o inicia sesi贸n.

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.

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

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

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

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;

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;

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.

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

Min 1:38

Spread Operator, important铆simo y muy 煤til para concatenar arrays y objetos

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,
    });
});

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.

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;
  }

Explicaci贸n del UPDATE del product.service.js

馃毇 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

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

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

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 馃槃

Mi clase de servicio:

Mi controlador o router:

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];
  }

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,
        });
    } 
});

隆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 鈥渘o 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 鈥渆stados鈥 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 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(鈥楢ccess-Control-Allow-Origin鈥, 鈥*鈥);
res.header(鈥楢ccess-Control-Allow-Headers鈥, 鈥楢uthorization, X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Allow-Request-Method鈥);
res.header(鈥楢ccess-Control-Allow-Methods鈥, 鈥楪ET, POST, OPTIONS, PUT, DELETE鈥);
res.header(鈥楢llow鈥, 鈥楪ET, 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 鈥榝aker鈥 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

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]
  }