Platzi
Platzi

LA EDUCACI脫N ES UN REGALO 隆ACCEDE AL PRECIO ESPECIAL!

Antes: $249
$149
Currency
Antes: $249
Ahorras: $100
COMIENZA AHORA
Termina en: 16D : 16H : 57M : 52S

Crea una cuenta o inicia sesi贸n

隆Contin煤a aprendiendo sin ning煤n costo! 脷nete y comienza a potenciar tu carrera

Rutas para usuarios

5/29
Recursos

Aportes 39

Preguntas 6

Ordenar por:

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

Podemos usar async/await si no queremos encadenar then y catch, wrappeando todo en un try catch

router.get("/", async (req, res) => {
    try {
        const list = await controller.list()
        response.success(req, res, list, 200)    
    } catch (error) {
        response.error(req, res, error.message, 500)
    }
});```


es muy facil perderte en esta clase!!

Les recomiendo que instalen JSON Viewer como extencion de Chrome para que analicen las respuestas de la API mas c贸modamente

Una peticion GET en el navegador se vera algo asi;

Podemos simplificar el codigo del controller preguntando por injected store y retornar las funciones directamente como arrows

module.exports = (injectedStore) => {
  if(!injectedStore) injectedStore = require("../../../store/dummy");

  return {
    list: () => injectedStore.list(TABLE),
    get: id => injectedStore.get(TABLE, id)
  };
};

Le solucione el reto asi:

Buenos dias,

Yo lo hice de la siguiente forma, por que? usando express, esta la posibilidad de capturar los parametros enviados por el body con la linea 7. con prueba y error hasta que al final pude capturar el body.

router.use(express.json());

Code:
components/user/networks.js

Resultado:

Anadi una validacion para asegurarse de que se recibe un numero

async function get(tabla, id) {
	let col = await list(tabla)
	let numId = parseInt(id)

	if (isNaN(numId)) {
		throw new Error('Parameter is not a number')
	}

	return col.filter(item =>  item.id === numId)[0] || null
}

Mi soluci贸n

// network.js

const express = require("express")

const response = require("../../../network/response");
const Controller = require("./index")

const router = express.Router();

router.get("/", (req, res) => {
    Controller.list()
        .then((list) => {
            response.success(req, res, list, 200)
        }).catch(err => {
            response.error(req, res, err.message, 500)
        })
})

router.get("/:id", (req, res) => {
    Controller.get(req.params.id)
        .then((user) => {
            response.success(req, res, user, 200)
        }).catch(err => {
            response.error(req, res, err.message, 500)
        })
})

router.get("/upsert/:id/:name", (req, res) => {
    Controller.upsert(req.params.id, req.params.name)
        .then((user) => {
            response.success(req, res, user, 200)
        }).catch(err => {
            response.error(req, res, err.message, 500)
        })
})

router.get("/delete/:id", (req, res) => {
    Controller.remove(req.params.id)
        .then((user) => {
            response.success(req, res, user, 200)
        }).catch(err => {
            response.error(req, res, err.message, 500)
        })
})

module.exports = router
// controller.js

const TABLE = "user"

module.exports = (injectedStore) => {
    let store = injectedStore
    if (!store) {
        store = require("../../../store/dummy")
    }

    return {
        list: () => store.list(TABLE),
        get: (id) => store.get(TABLE, id),
        upsert: (id, name) => store.upsert(TABLE, id, name),
        remove: (id) => store.remove(TABLE, id)
    }
}
// dummy.js

const db = {
    "user": [
        {
            id: "1",
            name: "Enrique"
        }
    ]
}

const list = async (table) => {
    return db[table];
}

const get = async (table, id) => {
    let collection = await list(table);
    return collection.find(item => item.id === id) || null
}

const upsert = async (table, id, name) => {
    let newUser = { id: id, name: name }
    db[table].push(newUser)
}

const remove = async (table, id) => {
    db[table].splice(Number(id) - 1, 1)
    return true
}


module.exports = {
    list,
    get,
    upsert,
    remove
}

Yo lo solucione asi:

dummy.js

const db = {
    'user': [
        { id: '1', name: 'Carlos'},
        { id: '2', name: 'Fernando'},
    ],
};

async function list(tabla) {
    return db[tabla];
};
async function get(tabla, id) {
    let col = await list(tabla);
    return col.filter( item => item.id === id)[0] || null;
};

async function upsert(tabla, data) {

    console.log(data)
    db[tabla].push(data);
    return data
}

async function remove(id) {

    for(let i = 0; i < db.user.length; i++){
        if(db.user[i].id == '2'){
            idRemoved = db.user[i].id;
            delete db.user[i];
            return `User with the id:${idRemoved} deleted`;
        }
    }
};

module.exports = {
    list,
    get,
    upsert,
    remove,
};

controller.js

const nanoid = require('nanoid');
// variable TABLE for user
const TABLA = 'user';

// function created to injec the store
module.exports = function(injectedStore) {
    // validating if store exist
    let store = injectedStore;
    if (!store) {
        store = require('../../../store/dummy');
    }
    // one validation is false use the function require from db
    function list() {
        return store.list(TABLA);
    }
    function get(id) {
        return store.get(TABLA, id);
    }

    function upsert(body) {
        console.log(body)
        const user = {
            name: body.name,
        }
        if (body.id) {
            user.id = body.id
        } else {
            user.id = nanoid()
        }

        return store.upsert(TABLA, user);
    }

    function remove(TABLA, id) {
        return store.remove(id);
    }


    return {
        list,
        get,
        upsert,
        remove,
    };
};

network.js

const express = require('express');

const response = require('../../../network/response');
const Controller = require('./index');

const router = express.Router();

router.get('/', function(req, res) {
    Controller.list()
        .then((lista) => {
            response.success(req, res, lista, 200);
        })
        .catch ((err) => {
            response.error(req, res, err.message, 500);
        });
})
router.get('/:id', function(req, res) {
    Controller.get(req.params.id)
        .then((user) => {
            response.success(req, res, user, 200);
        })
        .catch ((err) => {
            response.error(req, res, err.message, 500);
        });
});
router.post('/', function(req, res) {
    Controller.upsert(req.body)
        .then((user) => {
            response.success(req, res, user, 201);
        })
        .catch((err) => {
            response.error(req, res, err.message, 500);
        })
});

router.delete('/:id', function(req, res) {
    Controller.remove(req.params.id)
        .then((user) => {
            response.success(req, res, user, 200);
        })
        .catch((err) => {
            response.error(req, res, err.message, 500);
        });
});

Para usar nanoid tiene que bajarse a la version 2 para que les funcione. Y ademas, instalar body-parser para poder trabajar bien con el body.

npm i [email protected]^2.0.0
npm i body-parser

Espero que les sirva la info a los que van llegando

Los nombres de archivos me parecen confusos, asi como la estructura de las carpetas, quiza usando nombres mas descriptivos seria mejor

Mi c贸digo de user/network.js

// The express server
const { Router } = require('express');

// Required files for client responses and data controllers
const response = require('../../../network/responses');
const controller = require('./index');

// Instantiating express router
const router = Router();


// Set up the list of users
router.get('/', (req, res) => {
    controller.list()
        .then( list => {
            response.success( req, res, list, 200);
        })
        .catch( error => {
            response.error( req, res, error.message, 500);
        });
});

// Set up the user matching an id
router.get('/:id', (req, res) => {
    controller.get(req.params.id)
        .then( user => {
            response.success( req, res, user, 200);
        })
        .catch( error => {
            response.error( req, res, error.message, 500);
        });
});

module.exports = router;

Hay una parte que no le encuentro el sentido.
En el /api/user/index.js declaramos:

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

Pero en /api/user/controller.js cuando recibimos como prop ese store. Lo evaluamos si viene o no vac铆o. Y en caso de estarlo volvemos a declarar:

  if (!store) {
    ++store = require('../../../store/dummy');++
  }

Entiendo que si en index.js ya recurri贸 a 鈥樷/鈥/鈥/store/dummy鈥 para importar los datos. Y han venido vac铆os.
Por qu茅 en el controller tras ver que estan vac铆os volvemos a importar los datos del mismo fichero 鈥樷/鈥/鈥/store/dummy鈥.
驴Esto nos volver谩 a traer datos vac铆os no? 驴O me he perdido en alg煤n punto?

Saludos. 馃槃

Porque razon el parametro en el get de id, lleva dos puntos?
/:id, de otra forma no funciona

Mi soluci贸n al reto:
index.js

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

const config = require('./config.js');
const user = require('./api/components/user/network')

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
// router
app.use('/api/user', user);

app.listen(config.api.port, () => {
    console.log('Api escuchando en el puerto: ', config.api.port)
})

network.js

const express = require('express');
const router = express.Router();
const response = require('../../../network/response');
const Controller = require('./index');

router.get('/', (req, res) => {
    Controller.list()
        .then(users => {
            response.success(req, res, users, 200);
        }).catch(err => {
            response.error(req, res, err.message, 500);
        })
})

router.get('/:id', (req, res) => {
    Controller.getUser(req.params.id)
        .then(user => {
            response.success(req, res, user, 200);
        }).catch(err => {
            response.error(req, res, err.message, 500);
        })
})

router.post('/', (req, res) => {
    Controller.addUser(req.body.user)
        .then(user => {
            response.success(req, res, user, 200);
        }).catch(err => {
            response.error(req, res, err.message, 500);
        })
})

router.delete('/:id', (req, res) => {
    Controller.deleteUser(req.params.id)
        .then(user => {
            response.success(req, res, user, 200);
        }).catch(err => {
            response.error(req, res, err.message, 500);
        })
})

module.exports = router;

controller.js

const TABLA = 'users';

module.exports = function(injectedStore) {
    let store = injectedStore;
    if (!store) {
        store = require('../../../store/dummy');
    }

    function list() {
        return store.list(TABLA);
    }

    function getUser(id) {
        return store.get(TABLA, id)
    }

    function addUser(user) {
        return store.upsert(TABLA, user);
    }

    function deleteUser(id){
        return store.remove(TABLA, id);
    }

    return {
        list,
        getUser,
        addUser,
        deleteUser,
    }
}

dummy.js

let db = {
    users: [
        {id: 1, nombre: "Luis Berenguer"},
        {id: 2, nombre: "Jorge Dominguez"}
    ]
}

async function list(tabla) {
    return db[tabla];
}

async function get(tabla, id) {
    let col = await list(tabla);
    return col.filter(item => item.id == id)[0] || null;
}

async function upsert(tabla, data) {
    await db[tabla].push(data);
    return data;
}

async function remove(tabla, id) {
    const index = db[tabla].findIndex(item => item.id == id);
    db[tabla].splice(index, 1);
}

module.exports = {
    list,
    get,
    upsert,
    remove
}

para no modificar el tipo de dato de numeric a string:

async function get (table, id) {
    console.log('I recibed table: ', table)
    console.log('I recibed id: ', id)

    let collection = await list (table);
    return collection.filter(item => item.id === parseInt(id))[0]||null;
}

Hola a todos, alguien tiene documentaci贸n o algo que me recomienden ya que la parte de inyeccion se me hizo un poco compleja.

Comparto mi codigo usando async await y arrow functions

dummy,js

const db = {
  user: [{ id: "1", name: "Jos茅" }],
};
const list = async (table) => db[table];
const get = async (table, id) => {
  let col = await list(table);
  return col.filter((item) => item.id === id[0] || null);
};
const upsert = async (table, data) => {
  db[collection].push(data);
};
const remove = async (table, id) => true;

module.exports = {
  list,
  get,
  upsert,
  remove,
};

network.js

const express = require("express");
const router = express.Router();
const response = require("../../../network/response");
const controller = require("./index");

router.get("/", async (req, res) => {
  try {
    const list = await controller.list();
    response.success(req, res, list, 200);
  } catch (error) {
    response.error(req, res, error.message, 500);
  }
});

router.get("/:id", async (req, res) => {
  try {
    const list = await controller.get(req.params.id);
    response.success(req, res, list, 200);
  } catch (error) {
    response.error(req, res, error.message, 500);
  }
});

module.exports = router;
const express = require('express');
const response = require('../../../network/response');
const controller = require('./index');
const router = express.Router();

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

module.exports = router;

Que opina Carlos de utilizar Clases?
controller.js:

const TABLA = 'user';

module.exports = class UserController {

    constructor(store) {
        this.store = store || require('../../../store/dummy');
    }

    list() {
        return this.store.list(TABLA);
    }
}

index.js:

const store = require('../../../store/dummy');
const UserController = require('./controller');

module.exports = new UserController(store);

El controlador solo se crea una vez.

Esto responde a alg煤n patron de dise帽o??

Porque cuando en el navegador entr贸 a localhost:3001/api/user/1
Me muestra: Cannot GET /api/user/1

Y si le quito el id: 1 si muestra el objeto?

En la funci贸n remove consider茅 el caso en el que el id fuera inv谩lido para que lanzara un error y posteriormente fuera recogido en el catch de network

async function remove(tabla, id) {
	let coleccion = await list(tabla);
	let idValid = await get(tabla, id);
	if (idValid) {
		coleccion.splice(coleccion.indexOf(idValid), 1);
		//return `Usuario con id: ${id} eliminado correctamente`;
		return coleccion
	}

	throw {
		status: 400,
		details: 'No se encontr贸 el ID',
		message: 'Id inv谩lido'
	};
}

me perdi un poco en la ultima parte, espero comprender mas en siguientes clases

router.post('/', (req, res) => {
    Controller.upsert(req.body)
        .then((user) => {
            response.success(req, res, user, 201);
        })
        .catch((err) => {
            response.error(req, res, err.message, 500);
        })
})

al colocar en el navegador http://localhost:3000/api/user/1

me trae la lista de los usuarios.!

Alguien sabe por que.?

En el caso de la funcion para eliminar un user, me di cuenta que si desde un async function se retorna un error, cuando estamos esperando la respuesta de esta funcion no se entrara al catch. Investigando un poco aprendi que se debe hacer un throw:

async function remove(table, id) {
    const indexToDelete = db[table].findIndex(item => item.id === id);
    if(indexToDelete === -1 ){
        throw new Error("No se encontro el usuario");
    }
    db[table].splice(indexToDelete, 1);
    return id;
}

Para mas info al respecto pueden consultar este articulo

馃槂

store

async function upsert(tabla, data) {
    
    db[tabla].push({
        id: db[tabla].length +1,
        name: data
    })
}

controller

function addOne(data) {
    return injectedStore.upsert(TABLA, data);
  }

network.controller

aggOne = (req, res)=>{
    const {name} = req.body
    addOne(name).then(()=>{
        success(res,'dato agregado')
    }).catch(e=> failure(res,e))
}

Yo solucione la ruta del remove as铆;

async function remove(tabla, id){
  
   let table = await list(tabla);
   let index = table.indexOf(id);
   let remove = table.splice(index + 1, 1 );

   return {
       table,
       remove
   }

}

y en el navegador sale as铆;

// 20200814022329
// http://localhost:3000/api/user/remove/1

{
鈥渢able鈥: [
{
鈥渋d鈥: 2,
鈥渘ame鈥: 鈥渕iss鈥
}
],
鈥渞emove鈥: [
{
鈥渋d鈥: 1,
鈥渘ame鈥: 鈥渕iran鈥
}
]
}

Decid铆 cambiar un poco la estructuraci贸n del controller usar clases de js e ir definiendo las funciones (list, get, upsert, etc) como m茅todos de la clase UserController. (esto implica que en el index.js de user se exporte el controller como new UserController(store) ). Dejo mi codigo

const TABLE = 'user';

class UserController {
    constructor(injectedStore) {
        this.store = injectedStore;
        if (!this.store) {
            this.store = require('../../../store/dummy');
        }
    }

    list() {
        return this.store.list(TABLE);
    }

    get(id) {
        return this.store.get(TABLE, id); 
    }
}

module.exports = UserController;

Ejemplo con async await (Simplemente lo hace mas bonito, mas legible que las promesas鈥)
El resto del codigo seria igual

router.get('/', async (req, res) => {
    try {
        const list = await controller.list();
        console.log(list);
        response.success(req, res, list, 200);
    } catch (error) {
        response.error(req, res, "Error getting data", 500, error);
    }
});

隆Hola a todos!

Comparto mi soluci贸n en typescript del archivo network.
tambi茅n pueden dar un vistazo al repositorio y darme su opini贸n

github-repo

const newUser: RequestHandler = (req, res, next) => {
  const body = req.body;
  Controller.newOne(body)
    .then(() => {
      succes(req, res, 'Update ok', 201);
    })
    .catch((err) => {
      error(req, res, err, 500);
    });
};
const eraseUser: RequestHandler = (req, res, next) => {
  const id = req.params.id;
  Controller.deleteOne(id)
    .then(() => {
      succes(req, res, 'User deleted', 200);
    })
    .catch((err) => {
      error(req, res, err, 500);
    });
};

router.get('/', listAll);
router.get('/:id', oneUser);
router.post('/new', newUser);
router.delete('/:id', eraseUser);

He resuelto el reto. Me tard茅 mucho porque olvid茅 lo del body-parser y me salia que req.body era undefined

archivo principal

const express = require('express');

const config = require('../config.js');
const user = require('./components/user/network'); 
const bodyParser = require('body-parser');
const app = express();

//ROUTING
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use('/api/user', user);

app.listen(config.api.port, () => {
    console.log('API escuchando en el puerto ', config.api.port);
});

Dummy.js
En este caso agregu茅 db[tabla].length + 1 para que el id se incrementara en 1 cada que agreguemos un usuario

const db = {
    'user': [
        { id: '1', name: 'Julio'},
    ]
};

async function list(tabla) {
    return db[tabla];
}

async function get(tabla, id) {
    let collection = await list(tabla);
    console.log(tabla);
    console.log(collection);
    return collection.filter( item => item.id === id)[0] || null;
}

async function upsert(tabla, data) {
    const newData = {
        id: db[tabla].length + 1,
        data: data.name,
    }
    db[tabla].push(newData);
    return newData;
}

async function remove(tabla, id) {
    return true;
}

module.exports = {
    list,
    get, 
    upsert,
    remove
}

network.js

router.post('/', (req, res) => {
    console.log(req.body);
    controller.insert(req.body)
        .then(user => {
            response.success(req, res, user, 201);
        })
        .catch((err) => {
            response.error(req, res, err.message, 500);
        })

});

controller.js

const TABLA = 'user';

module.exports = function (injectedStore) {
    let store = injectedStore;
    
    if (!store) {
        store = require('../../../store/dummy');
    }

    function list() {
        return store.list(TABLA);
    }
    
    function get(id) {
        return store.get(TABLA, id);
    }

    function insert(data) {
        if (!data.name) {
            return Promise.reject('No se encontro el valor de name');
        }

        const user = {
            name: data.name,
        }

        return store.upsert(TABLA, user);
    }

    return {
        list,
        get,
        insert,
    };
}

Llevo rato batallando con el ejercicio y solo ten铆a que agregar el body parser 馃槮

Voy a dejar la forma en como se puede solucionar el remove el upser es simplemente un push a si que no hay mucha ciencia

Creo que la mayoria va tratar de hacerlo con un bucle a si que se los voy a dejar en forma de bucle, pero tengan en cuenta que esto ocupa mucha memoria a si esto no es lo mas conveniente

async function remove(table, idDelete) {
  let data = [];
  let collection = await list(table);

  collection.map((element) => {
    if (element.id != idDelete) data.push(element)
  });

  db[table] = data;
  console.log(db)
  return `Element is delete`;

}

Ahora bien鈥 la forma correcta a mi entender es con un findindex() para obtener el indice y ese borrarlo

async function remove(table, idDelete) {

  const ref = db[table].findIndex(item => item.id === idDelete)
  if (ref >= 0) db[table].splice(ref, 1)

  console.log(db)

  return `Element is delete`;

}

Ahora podemos usar Nullish operators

const store = injectedStore ?? require('@store/dummy')

Con ES2020

Que loco express no me todo get

Reto cumplido, en el index,js agrego esto para leer formatos json

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

en network.js creo las rutas para cada acci贸n

router.post('/inset',function (req, res){
      controller.insert(req.body)
            .then((data)=>{
                  response.success(req, res, data, 200)
            }).catch((error) => {
                  response.error(req,res,error,500)
             })
})
router.patch('/update',function(req, res){
      controller.update(req.body)
            .then((data)=>{
                  response.success(req, res, data, 200)
            }).catch((error) => {
                  response.error(req,res,error,500)
            })
})
router.delete('/delete',function(req, res){
      controller.remove(req.body.id)
            .then((data)=>{
                  response.success(req, res, data, 200)
            }).catch((error) => {
                  response.error(req,res,error,500)
            })
})

en controller.js tambien puedo verificar la integridad de los datos y demas, de momento solo lo hice as铆

function insert(data){
            return store.insert(TABLE, data)
      }
 function update(data){
            return store.update(TABLE, data)
      }
 function remove(id){
            return store.remove(TABLE,id)
      }

por ultimo en el dummy.js hice varias cosas para simular las operaciones y de paso practicar JS

async function insert(table, data){
      return await db[table].push(data)
}

function update(table, data){
      return new Promise(async (resolve,reject)=> {
            let col = await list(table)
            col.filter(item =>{
                  if(item.id === data.id){
                        item.name = data.name
                        resolve(item)
                  }
            })
            reject('Algo salio mal')
      })
}

function remove(table, id){
      return new Promise(async (resolve,reject) =>{
            let col = await list(table)
            let cont = 0
            await col.filter(item => {
                  if(item.id===id){
                        col.splice(cont,1)
                        resolve(`usuario ${item.id} elimunado`)
                  }
                  cont++
            })
            reject('Error al eliminar al usuario')
      })
}
const db = {
    'user': [
        { id: '1', name: 'Carlos'},
        { id: '2', name: 'Fernando'},
    ],
};

async function list(tabla) {
    return db[tabla];
};
async function get(tabla, id) {
    let col = await list(tabla);
    return col.filter( item => item.id === id)[0] || null;
};

async function upsert(tabla, data) {

    console.log(data)
    db[tabla].push(data);
    return data
}

async function remove(id) {

    for(let i = 0; i < db.user.length; i++){
        if(db.user[i].id == '2'){
            idRemoved = db.user[i].id;
            delete db.user[i];
            return `User with the id:${idRemoved} deleted`;
        }
    }
};

module.exports = {
    list,
    get,
    upsert,
    remove,
};

Aqu铆 empieza el cambio de las rutas a una promesa