John Cardozo
John Cardozo
REpresentational State Transfer
Estilo de arquitectura de software que define un conjunto de restricciones que serán usadas en servicios web.
cliente
servidor
http
endpoint
Formato de datos de transferencia
JSON o XML
Interface uniforme
Cliente - Servidor
Sin estado (stateless)
Cacheable
Sistema por capas (layered)
Separa de interfaz gráfica de lógica de negocio. Mejora la portabilidad y escalabilidad
Principio de generalidad, identificación de recursos, mensajes auto-descriptivos
El servidor no almacena nada acerca de la última petición. No sesión, no histórico
Mejora el desempeño del lado cliente y mejora la escalabilidad del servidor. Reduce carga.
Permite el uso de arquitectura por capas publicando el API en el servidor A, almacenando datos en el servidor B y autenticando las peticiones en el servidorC, por ejemplo.
Create
Read
Update
Delete
POST
GET
PATCH
DELETE
operaciones de datos
métodos http
CRUD
PETICIONES
[{id:1, titulo:"correr"}, {id:2, titulo:"leer"}]
Crear una tarea
Obtener todas las tareas
Modificar una tarea
Eliminar una tarea
POST /tareas
GET /tareas
PATCH /tareas/1
DELETE /tareas/1
{id:1, titulo:"correr"}
Obtener una tarea
GET /tareas/1
{titulo: "correr"}
{id:1, titulo:"correr"}
+
{titulo: "leer"}
+
{id:1, titulo:"leer"}
{id:1, titulo:"leer"}
Cliente
Servidor App
Servidor BD
web
móvil
escritorio
nodejs
express
Mongodb
RestAPI
Mongoose
JSON
RestAPI client
VS Code
Nodejs
Express
Insomnia
Firefox
MongoDB
Local
Robo3T
Cloud
Express es un framework de aplicaciones que provee un conjunto robusto de características para aplicaciones web y móviles
Node.js
Motor de ejecución
Javascript
Instalación
Verificación
node --version
npm --version
Node Package Manager
Node
Inicialización del proyecto
npm init -y
Instalación de Express
npm install express nodemon mongoose dotenv cors axios
Genera el folder node_modules
Si se está usando git se debe crear el archivo .gitignore que excluye el folder node_modules del repositorio de código
"scripts": {
"start": "nodemon app.js"
}
Configuración de package.json
axios sólo se usa para probar el API en el proyecto. Esta librería se utiliza usualmente en el cliente.
express
nodemon
mongoose
dotenv
cors
axios
framework web
reinicia la app automáticamente ante algún cambio
conexión a Mongodb desde Javascript
carga variables de ambiente desde un archivo .env
acceso a recursos desde diferentes orígenes
cliente HTTP para peticiones remotas
Creación de archivo app.js
// Importar express
const express = require("express");
// Creación de la aplicación
const app = express();
// Rutas
app.get("/", (req, res) => {
res.send("Hello Express");
});
app.get("/tareas", (req, res) => {
res.send("Estamos en tareas");
});
// Inicio del servidor
app.listen(3000);
Ejecución de la aplicación
npm start
const express = require("express");
// Creación del router
const router = express.Router();
// Creación de ruta
router.get("/", (req, res) => {
res.send("TAREAS");
});
// Exportar el router
module.exports = router;
routes/tareas.js
app.js
// Rutas
const tareasRoute = require('./routes/tareas')
// Middleware
app.use('/tareas', tareasRoute);
post
get
insomnia
postman
Clientes API
formulario
Método http
URL
Código de respuesta
Respuesta
Body
Formato del body
insomnia
<user>
<password>
<url>
<dbname>
usuario
qwerty
cluster0.xxx.mongodb.net
base_datos
mongodb+srv://<user>:<password>@<url>/<db_name>?retryWrites=true&w=majority
Para servidor local usar 127.0.0.1
Estructura de la Cadena de Conexión
mongodb://app:123@127.0.0.1/tareasdb?retryWrites=true&w=majority
Ejemplos de Cadena de Conexión
mongodb+srv://app:123@cluster0.xxx.mongodb.net/tareasdb?retryWrites=true&w=majority
Local
Remoto
mongodb://<user>:<password>@<url>/<db_name>?retryWrites=true&w=majority
// Carga el archivo .env
require("dotenv").config();
// Acceso a la variable de entorno
console.log(process.end.DB_CONNECTION)
Archivo .env
DB_CONNECTION=mongodb+srv://usuario:qwerty@127.0.0.1/tareasdb?retryWrites=true&w=majority
Código Javascript para cargar dotenv
El archivo .env debe ir en la raíz del proyecto
const mongoose = require("mongoose");
mongoose.connect(
process.env.DB_CONNECTION,
{ useUnifiedTopology: true, useNewUrlParser: true },
(err) => {
if (err) console.log(err);
else console.log("Conectado a la base de datos...");
}
);
Promises
const mongoose = require("mongoose");
const conexionBD = async () => {
try {
await mongoose.connect(process.env.DB_CONNECTION, {
useUnifiedTopology: true,
useNewUrlParser: true,
});
console.log("Conectado a la BD...");
} catch (error) {
console.log("Error de conexión a la BD...");
console.log(error);
}
};
// Invocación de la función
conexionBD();
async / await
// Importa la función de conexión
const { conexionBD } = require("./conexion");
// Carga las variables de entorno del archivo .env
require("dotenv").config();
// Invoca la función de conexión a la BD
conexionBD();
app.js
const mongoose = require("mongoose");
const conexionBD = async () => {
try {
// Conexion a la base de datos
await mongoose.connect(process.env.DB_CONNECTION, {
useUnifiedTopology: true,
useNewUrlParser: true,
});
console.log("Conectado a la BD...");
} catch (error) {
console.log("Error de conexión a la BD...");
console.log(error);
}
};
module.exports = { conexionBD };
conexion.js
Mongoose schema
const mongoose = require('mongoose');
// Definición del esquema
const TareaSchema = mongoose.Schema({
titulo: {
type: String,
required: true
},
descripcion: String,
terminada: {
type: Boolean,
default: false
},
fecha: {
type: Date,
default: Date.now
}
})
// Exportar el esquema
module.exports = mongoose.model('Tarea', TareaSchema);
// Middleware para procesar
// el body de las peticiones
app.use(express.json());
routes/tareas.js
app.js
const Tarea = require("../models/tarea");
router.post("/", async (req, res) => {
try {
// Crea el objeto
const tarea = new Tarea({
titulo: req.body.titulo,
descripcion: req.body.descripcion,
fecha: req.body.fecha
});
// Guarda el objeto en la base de datos
let resultado = await tarea.save();
// Retorna la respuesta al cliente
return res.json(resultado);
} catch (error) {
// Retorna el error al cliente
return res.status(500).send(error);
}
});
routes/tareas.js
const Tarea = require("../models/tarea");
router.get("/", async (req, res) => {
try {
// Obtiene todas las tareas
const tareas = await Tarea.find();
// retorna la respuesta al cliente
return res.json(tareas);
} catch (error) {
// Retorna el error al cliente
return res.status(500).send(error);
}
});
routes/tareas.js
const Tarea = require("../models/tarea");
router.get("/:id", async (req, res) => {
try {
// Obtiene una tarea por su id
const tarea = await Tarea.findById(req.params.id);
// retorna la respuesta al cliente
return res.json(tarea);
} catch (error) {
// Retorna el error al cliente
return res.status(500).send(error);
}
});
routes/tareas.js
const Tarea = require("../models/tarea");
router.put("/:id", async (req, res) => {
// Obtiene el body
const body = req.body;
// Obtiene el id
const id = req.params.id;
try {
// Actualiza la tarea dado su id
const resultado = await Tarea.findOneAndUpdate(
{ _id: id },
body,
{
new: true
}
);
// Retorna la respuesta al cliente
return res.json(resultado);
} catch (error) {
// Retorna el error al cliente
return res.status(500).send(error);
}
});
updateMany modifica varios documentos
routes/tareas.js
const Tarea = require("../models/tarea");
router.delete("/:id", async (req, res) => {
try {
// Elimina la tarea dado su id
const resultado = await Tarea.deleteOne({ _id: req.params.id });
// Retorna la respuesta al cliente
return res.json(resultado);
} catch (error) {
// Retorna el error al cliente
return res.status(500).send(error);
}
});
deleteMany elimina varios documentos
cliente
servidor
Mismo origen
Diferentes orígenes
OK
Error
app.js
const cors = require('cors');
// MIDDLEWARES
app.use(cors());
CORS es un mecanismo basado en headers HTTP que le permite a un servidor procesar cualquier origen (dominio, esquema, o puerto) diferente a su origen propio y le permita a un browser la carga de recursos
Este ejemplo muestra cómo se puede consumir un RestAPI desde Javascript utilizando la librería Axios
// Hace la petición al Rest API
let respuesta = axios.get("http://localhost:3000/tareas");
// No muestra la respuesta del servidor
console.log(respuesta);
- Hace la petición al servidor
- Javascript no espera a que se obtenga respuesta
- Ejecuta la siguiente instrucción
Muestra null porque se ejecuta antes de que se obtenga la información del servidor
uso de async/await
async function obtenerDatos() {
// Hace la petición al Rest API
let respuesta = await axios.get("http://localhost:3000/tareas");
// Muestra la respuesta obtenida del servidor
console.log(respuesta);
}
Para usar await, la instrucción debe estar en un bloque async
const axios = require('axios')
// Crea una tarea
async function crearTarea() {
try {
// Hace la petición al Rest API
let respuesta = await axios.post("http://localhost:3000/tareas",
{
titulo: "correr",
});
// Muestra el resultado
console.log(respuesta);
} catch (error) {
console.log(error);
}
}
// Invoca la función
crearTarea();
const axios = require('axios')
// Obtiene todas las tareas
async function obtenerTodaslasTareas(){
try {
// Hace la petición al Rest API
let tareas = await axios.get("http://localhost:3000/tareas");
// Muestra las tareas
console.log(tareas.data);
} catch (error) {
console.log(error);
}
}
// Invoca la función
obtenerTodaslasTareas();
const axios = require('axios')
async function obtenerTarea(id) {
try {
// Hace la petición al Rest API
let tarea = await axios.get(`http://localhost:3000/tareas/${id}`);
// Muestra la tarea
console.log(tarea.data);
} catch (error) {
console.log(error);
}
}
// Invoca la función
obtenerTarea('5f926234c8d7e2e7ecfb4eab');
const axios = require('axios')
async function modificarTarea(id) {
try {
// Hace la petición al Rest API
let respuesta = await axios.patch(`http://localhost:3000/tareas/${id}`,
{
titulo: "caminar",
});
// Muestra el resultado
console.log(respuesta.data);
} catch (error) {
console.log(error);
}
}
// Invoca la función
modificarTarea('5f926c060913e4ea3e7f93c4');
const axios = require('axios')
async function eliminarTarea(id) {
try {
// Hace la petición al Rest API
let respuesta = await axios.delete(`http://localhost:3000/tareas/${id}`);
// Muestra el resultado
console.log(respuesta.data);
} catch (error) {
console.log(error);
}
}
// Invoca la función
eliminarTarea('5f925f0d2d7376e74edccd8c');
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test de Tareas</title>
</head>
<body>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
// Función que obtiene todas las tareas
async function obtenerTodaslasTareas() {
try {
// Hace la petición al Rest API
let tareas = await axios.get("http://localhost:3000/tareas");
// Muestra las tareas
console.log(tareas.data);
} catch (error) {
console.log(error);
}
}
// Invoca la función
obtenerTodaslasTareas();
</script>
</body>
</html>
johncardozo@gmail.com