Entornos de desarrollo

1º DAM/DAW - Curso 2024-2025

User Tools

Site Tools


apuntes:backend_frontend

Desarrollo de aplicaciones: backend + frontend

frontendbackend.jpg
Figure 1: Frontend vs Backend (Fuente: https://ecdisis.com/que-es-frontend-y-backend/)

Configuración del proyecto

Crear un fichero package.json:

{
  "name": "cities-backend",
  "version": "0.1",
  "description": "A sample project to learn Node.js",
  "type": "module",
  "scripts": {
    "start": "node src/app.js"
  },
  "author": "Santiago Faci",
  "license": "GPL-2.0-only",
 
  "dependencies": {
    "express": "^4.21.1"
  }
}

Algunos comandos útiles:

  • npm init: Crear un fichero package.json de forma interactiva (si se añade –yes se rellenará directamente con valores por defecto)
  • npm run: Lista los scripts disponibles
  • npm run <nombre_script: Ejecuta el script cuyo nombre se para como parámetro
  • npm start: Ejecuta el script start (se puede ejecutar sin añadir run al tratarse de uno de los scripts definidos por nodejs)

Gestión de dependencias

Añadir las dependencias necesarias para el proyecto al fichero package.json en la sección dependencies (se pueden ir añadiendo a medida que son necesarias durante el desarrollo del proyecto):

. . .
"dependencies": {
    "express": "^4.21.1"
  }
. . .

Instalar todas las dependencias necesarias para el proyecto:

npm install

Actualizar las dependencias necesarias para el proyecto, si es necesario:

npm update

También se pueden instalar una dependencia concreta y ésta será añadida automáticamente al fichero package.json como tal:

npm install express

Backend

¿Qué es una API?

Figure 2: Web API (Fuente: https://www.programmingwithmukesh.com/articles/web-api)
Figure 3: Tipos de operaciones en una Web API

API sencilla sólo lectura

import express from 'express';
 
const app = express();
app.use(express.json());
 
const cities = {
    'Zaragoza': {
        altitude: 199,
        population: 673010
    },
    'Huesca': {
        altitude: 488,
        population: 53305
    },
    'Teruel': {
        altitude: 915,
        population: 25900
    }
};
 
app.get('/cities', (req, res) => {
    res.json(cities);
});
 
app.get('/city/:city', (req, res) => {
    const city = req.params.city;
    res.json(cities[city]);
});
 
 
app.listen(8080, () => {
    console.log('Iniciando el backend en el puerto 8080');
});

Asumiendo que tenemos un fichero package.json como el explicado anteriormente, podremos ejecutar la API con el siguiente comando:

npm start

Y tendremos los siguiente endpoints disponibles:

Figure 4: Listado de todas las ciudades
Figure 5: Detalles de una ciudad concreta

También podemos utilizar aplicaciones como Hoppscotch que son específicas para desarrolladores. Son clientes diseñados para realizar llamadas a APIs y testear que éstas funcionan correctamente.

Figure 6: Hoppscotch

Frontend

{
    "name": "cities-frontend",
    "version": "0.1",
    "source": "src/index.html",
    "type": "module",
    "scripts": {
        "start": "parcel --no-cache",
        "build": "parcel build"
    },
    "devDependencies": {
        "buffer": "^6.0.3",
        "parcel": "latest",
        "process": "^0.11.10"
    },
    "dependencies": {
        "axios": "^1.7.7"
    }
}
<!DOCTYPE html>
<html>
    <head>
        <title>Ejemplo 1: API con Node.js</title>
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
        <script type="module" src="app.js"></script>
    </head>
    <body onload="readCities()">
        <div class="container">
            <h1>Ejemplo de API con Node.js</h1>
            <img src="nodejs.png"/>
            <ul id="cities" class="list-group">
            </ul>
        </div>
    </body>
</html>
import axios from 'axios';
 
function addCityNode(name) {
    const citiesUl = document.getElementById('cities');
 
    const item = document.createElement('li');
    item.className = 'list-group-item';
    item.appendChild(document.createTextNode(name));
    citiesUl.appendChild(item);
};
 
window.readCities = function() {
    axios.get('http://localhost:8080/cities')
        .then((response) => {
            const cityList = response.data;
 
            Object.keys(cityList).forEach(cityName => {
                addCityNode(cityName);
            });
        });
};

Tal y como hacemos con el backend, podremos ejecutar este frontend con el siguiente comando:

npm start

Hay que tener en cuenta que backend y frontend debes escuchar en puertos diferentes para poder ejecutarse al mismo tiempo. En nuestro caso el backend escucha en el puerto 8080 y el frontend en el 1234

Figure 7: cities-frontend

CRUD Backend + Frontend

Una vez que hemos visto una sencilla API con unicamente un par de operaciones de lectura, vamos a ver un ejemplo algo más completo. Es lo que también se conoce como CRUD que es el acrónimo que se utiliza para referirse a las 4 operaciones básica que permite que los usuarios puedan registrar (Create), leer (Read), modificar (Update) y borrar (Delete) información utilizando algún tipo de software.

En el caso de la API (backend) deberán ser diseñadas conforme a las convenciones que vimos un poco antes cuando explicamos lo que era una API.

Backend

import express from 'express';
import cors from 'cors';
 
const app = express();
app.use(cors());
app.use(express.json());
 
const cities = {
    'Zaragoza': {
        altitude: 199,
        population: 673010
    },
    'Huesca': {
        altitude: 488,
        population: 53305
    },
    'Teruel': {
        altitude: 915,
        population: 25900
    }
};
 
app.get('/cities', (req, res) => {
    res.json(cities);
});
 
app.get('/city/:city', (req, res) => {
    const city = req.params.city;
    res.json(cities[city]);
});
 
app.post('/cities', (req, res) => {
    const name = req.body.name;
    const altitudeValue = req.body.altitude;
    const populationValue = req.body.population;
 
    cities[name] = {
        altitude: altitudeValue,
        population: populationValue
    };
    console.log(cities);
    res.status(201).end();
});
 
app.listen(8080, () => {
    console.log('Iniciando el backend en el puerto 8080');
});

Frontend

<!DOCTYPE html>
<html>
    <head>
        <title>Ejemplo 1: API con Node.js</title>
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
        <script type="module" src="app.js"></script>
    </head>
    <body onload="readCities()">
        <div class="container">
            <h1>Ejemplo de API con Node.js</h1>
            <img src="nodejs.png"/>
            <ul id="cities" class="list-group">
            </ul>
            <hr/>
            <form>
                <div class="mb-3">
                    <label for="name" class="form-label">Nombre</label>
                    <input class="form-control" type="text" id="name"/>
                </div>
                <div class="mb-3">
                    <label for="altitude" class="form-label">Altitud</label>
                    <input class="form-control" type="text" id="altitude"/>
                </div>
                <div class="mb-3">
                    <label for="population" class="form-label">Población</label>
                    <input class="form-control" type="text" id="population"/>
                </div>
                <button type="button" class="btn btn-primary" onClick="addCity()">Add city</button>
            </form>
        </div>
    </body>
</html>
import axios from 'axios';
 
function addCityNode(name) {
    const citiesUl = document.getElementById('cities');
 
    const item = document.createElement('li');
    item.className = 'list-group-item';
    item.appendChild(document.createTextNode(name));
 
    const button = document.createElement('button');
    button.className = 'btn-close'
    button.onclick = function() {
        removeCity(name);
        item.remove();
    };
    item.appendChild(button);
 
    citiesUl.appendChild(item);
};
 
window.readCities = function() {
    axios.get('http://localhost:8080/cities')
        .then((response) => {
            const cityList = response.data;
 
            Object.keys(cityList).forEach(cityName => {
                addCityNode(cityName);
            });
        });
};
 
window.addCity = function() {
    const name = document.getElementById('name').value;
    const altitude = document.getElementById('altitude').value;
    const population = document.getElementById('population').value;
 
    if (name === '') {
        alert('El nombre es un campo obligatorio');
        return;
    }
 
    axios.post('http://localhost:8080/cities', {
        name: name,
        altitude: altitude,
        population: population
    }).then(() => {
        addCityNode(name);
    });
};
 
window.removeCity = function(name) {
    console.log(name + ' was removed');
    // TODO Remove the city
};
Figure 8: cities-frontend-crud

Proyectos de ejemplo

Todos los proyectos de ejemplo de esta parte están en el repositorio nodejs de GitHub.


© 2024 Santiago Faci

apuntes/backend_frontend.txt · Last modified: 2024/10/14 18:47 by Santiago Faci