====== Desarrollo de aplicaciones: backend + frontend ======
===== Configuración del proyecto =====
Crear un fichero [[https://docs.npmjs.com/creating-a-package-json-file|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 [[https://docs.npmjs.com/cli/v10/configuring-npm/package-json|Especificación completa para el fichero package.json]]
===== 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? ====
==== 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:
* http://localhost:8080/cities: Para ver el listado de todas las ciudades en formato JSON
* http://localhost:8080/city/Zaragoza: Para ver los datos de una ciudad concreta (en este caso Zaragoza pero podríamos indicar cualquiera de las existentes)
También podemos utilizar aplicaciones como [[https://hoppscotch.com/|Hoppscotch]] que son específicas para desarrolladores. Son clientes diseñados para realizar llamadas a APIs y testear que éstas funcionan correctamente.
===== 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"
}
}
Ejemplo 1: API con Node.js
Ejemplo de API con Node.js
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
===== 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 [[https://en.wikipedia.org/wiki/Create,_read,_update_and_delete|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 [[https://entornos-desarrollo.codeandcoke.com/_detail/apuntes:urls.png?id=apuntes%3Abackend_frontend|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 ====
Ejemplo 1: API con Node.js
Ejemplo de API con Node.js
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
};
====== Proyectos de ejemplo ======
Todos los proyectos de ejemplo de esta parte están en el repositorio [[https://github.com/codeandcoke/nodejs|nodejs]] de GitHub.
----
(c) 2024 Santiago Faci