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 (con extensión .json).

Actividades en clases

Github

  1. Cree un repositorio en GitHub con el nombre restapi.
  2. Asegúrese de marcar la opción Add .gitignore y seleccione la opción Node.
  3. 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), body-parser (manejar solicitudes con datos en el cuerpo del requerimiento) y dotenv (variables de entorno del proyecto).

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

     npm install firebase-admin
    
  4. Cree el archivo para las variables de entorno del proyecto (.env), con las variables PORT y FIREBASE_ADMIN_API

     PORT=5500
     FIREBASE_ADMIN_API = ''
    
  5. Copie el contenido del archivo con la clave acceso con contenido de la variable FIREBASE_ADMIN_API:

     FIREBASE_ADMIN_API='{
       "type": "service_account",
       ...
       "universe_domain": "googleapis.com"
     }'
    
  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:

     require('dotenv').config()
    
     const express = require('express');
     const bodyParser = require('body-parser');
     const admin = require('firebase-admin');
     const serviceAccount = JSON.parse(process.env.FIREBASE_ADMIN_API)
    
     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": "node server.js",
         "autostart": "nodemon server.js",
         ...
       }
     ...
    
  2. (STOP 3) Desde la línea de comandos, inicie el servidor:

     npm run autostart
    

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:5500/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:5500/api/items -H "Accept: application/json" 
    
  2. (STOP 4) Revise el resultado en la línea de comandos.

Actividad en grupo

En grupos de tres (3) personas, completen las siguientes tareas. Pueden utilizar la documentación oficial o los servicios de 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:5500/api/items/%ID% -H "Accept: application/json" 
    
         curl -X PUT http://localhost:5500/api/items/%ID% -H "Content-Type: application/json" -d "{\"tags\":\"\",\"question\":\"\",\"answers\":\"\"}"
    
         curl -X DELETE http://localhost:5500/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

Términos

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

Referencias