DAWM

Guía 15

DAWM / Proyecto04

Actividades previas

Entorno de desarrollo

  1. En el terminal, verifica que tengas instalado NodeJS y NPM, con:

     node -v
     npm -v
    

Firebase - Firestore

  1. Realice el tutorial completo de Firebase - Firestore.
  2. Descargue el archivo con la clave acceso y cambie el nombre del archivo por firebaseConfig.json.

Actividades en clases

Github

  1. Cree un repositorio en GitHub con el nombre restapi.
  2. Clone y acceda a la carpeta en el directorio local.

Express - Estructura base y configuración

  1. Inicialice un nuevo proyecto de Node.js, con:

     npm init -y
    
  2. Instale las dependencias Express (framework de backend), nodemon (para reiniciar el servidor automáticamente durante el desarrollo) y body-parser (manejar solicitudes con datos en el cuerpo del requerimiento).

     npm install express body-parser
     npm install --save-dev nodemon
    
  3. Instale el Firebase Admin SDK.

     npm install firebase-admin
    
  4. Cree la carpeta ./config.
  5. Mueva el archivo descargado previamente (firebaseConfig.json) dentro de la carpeta ./config.
  6. (STOP 1) Revise la estructura de archivos.

Express - Servidor, enrutador y controlador

  1. Cree el archivo ./server.js con el código del servidor:

     const express = require('express');
     const bodyParser = require('body-parser');
     const admin = require('firebase-admin');
     const serviceAccount = require('./config/firebaseConfig.json');
    
     admin.initializeApp({
       credential: admin.credential.cert(serviceAccount)
     });
    
     const app = express();
     app.use(bodyParser.json());
    
     const PORT = process.env.PORT || 5000;
    
     app.use('/api', require('./routes/api'));
    
     app.listen(PORT, () => {
       console.log(`Server is running on port ${PORT}`);
     });
    
  2. Cree el archivo ./routes/api.js con el código del manejador de rutas o enrutador:

     const express = require('express');
     const router = express.Router();
     const itemController = require('../controllers/itemController');
    
     router.post('/items', itemController.createItem);
     router.get('/items', itemController.getAllItems);
    
     module.exports = router;
    
  3. Cree el archivo ./controllers/itemController.js con el código del controlador:

     const admin = require('firebase-admin');
     const db = admin.firestore();
    
     exports.createItem = async (req, res) => {
       try {
         const data = req.body;
         const itemRef = await db.collection('items').add(data);
         res.status(201).send(`Created a new item: ${itemRef.id}`);
       } catch (error) {
         res.status(400).send(error.message);
       }
     };
    
     exports.getAllItems = async (req, res) => {
       try {
         const itemsSnapshot = await db.collection('items').get();
         const items = [];
         itemsSnapshot.forEach((doc) => items.push({ id: doc.id, ...doc.data() }));
         res.status(200).json(items);
       } catch (error) {
         res.status(400).send(error.message);
       }
     };
    
  4. (STOP 2) Verifica la estructura de carpetas y archivos.

Ejecución del servidor

  1. Agregue el script start en ./package.json.

     ...
       "scripts": {
         "start": "nodemon server.js",
         ...
       }
     ...
    
  2. (STOP 3) Desde la línea de comandos, inicie el servidor:

     npm start
    

Verificación

  1. Desde una nueva línea de comandos, utilice cURL para realizar las peticiones al REST API:

    • Petición método HTTP POST
     curl -X POST http://localhost:5000/api/items -H "Content-Type: application/json" -d "{\"tags\":[\"tag1\",\"tag2\"],\"question\":\"Which band?\",\"answers\":[{\"id\":\"a0\",\"answer\":\"Answer1\"},{\"id\":\"a1\",\"answer\":\"answer2\"}]}"
    
    • Petición método HTTP GET
     curl -X GET http://localhost:5000/api/items -H "Accept: application/json" 
    
  2. (STOP 4) Revise el resultado en la línea de comandos.
  3. Versiona local y remotamente el repositorio restapi.

Actividad en grupo

En grupos de tres (3) personas, completen las siguientes tareas. Pueden utilizar la documentación oficial o un LLM.

  1. Complete el código del controlador ./controllers/itemController.js con las operaciones CRUD con el Firebase Admin SDK. Como parte de la respuesta, considere los estados HTTP (200, 400 y 404).

     ...
     exports.getItem = async (req, res) => { }
     exports.updateItem = async (req, res) => { }
     exports.deleteItem = async (req, res) => { }
     ...
    
    Haga click aquí para ver la solución
    
         exports.getItem = async (req, res) => {
    
             try {
                 const itemId = req.params.id;
                 const itemDoc = await db.collection('items').doc(itemId).get();
                 if (!itemDoc.exists) {
                     res.status(404).send('Item not found');
                 } else {
                     res.status(200).json({ id: itemDoc.id, ...itemDoc.data() });
                 }
             } catch (error) {
                 res.status(400).send(error.message);
             }
    
         };
    
         exports.updateItem = async (req, res) => {
    
             try {
                 const itemId = req.params.id;
                 const data = req.body;
                 const itemRef = db.collection('items').doc(itemId);
                 await itemRef.update(data);
                 res.status(200).send('Item updated');
             } catch (error) {
                 res.status(400).send(error.message);
             }
    
         };
    
         exports.deleteItem = async (req, res) => {
    
             try {
                 const itemId = req.params.id;
                 await db.collection('items').doc(itemId).delete();
                 res.status(200).send('Item deleted');
             } catch (error) {
                 res.status(400).send(error.message);
             }
    
         };
       
  2. Complete el código del enrutador ./routes/api.js con las relaciones de los métodos HTTP con las funciones del controlador:

     ...
     router.get(      ,     );
     router.put(      ,     );
     router.delete(   ,     );
     ...
    
    Haga click aquí para ver la solución
    
         router.get('/items/:id', itemController.getItem);
         router.put('/items/:id', itemController.updateItem);
         router.delete('/items/:id', itemController.deleteItem);
       
  3. Utilice otra línea de comandos para verificar el funcionamiento de su REST API mediante peticiones cURL.

    Haga click aquí para ver la solución
    
    
         set ID=#ID de un objeto almacenado#
    
         curl -X GET http://localhost:5000/api/items/%ID% -H "Accept: application/json" 
    
         curl -X PUT http://localhost:5000/api/items/%ID% -H "Content-Type: application/json" -d "{\"tags\":\"\",\"question\":\"\",\"answers\":\"\"}"
    
         curl -X DELETE http://localhost:5000/api/items/%ID% -H "Accept: application/json" 
          
       
  4. (STOP 5) Revise el resultado en la línea de comandos.
  5. Versiona local y remotamente el repositorio restapi.

Documentación

Fundamental

Arquitectura

Términos

framework, backend, servidor, enrutador, controlador, SDK, CRUD, métodos HTTP, estados HTTP

Referencias