rest api:
express+mongodb

John Cardozo

John Cardozo

rest api:
express+mongodb

qué es rest api?

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

características de rest api

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.

funciones de persistencia & métodos http

Create

Read

Update

Delete

POST

GET

PATCH

DELETE

operaciones de datos

métodos http

CRUD

PETICIONES

acciones y peticiones http

[{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"}

arquitectura de trabajo

Cliente

Servidor App

Servidor BD

web

móvil

escritorio

nodejs

express

Mongodb

RestAPI

Mongoose

JSON

RestAPI client

herramientas

VS Code

Nodejs

Express

Insomnia

Firefox

MongoDB

Local

Robo3T

Cloud

qué es express?

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

nodejs

Instalación

Verificación

node --version

npm --version

Node Package Manager

Node

configuración inicial del proyecto

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.

descripcion de paquetes

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

hello express

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

rutas en archivos separados

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);

clientes api

post

get

insomnia

postman

Clientes API

formulario

prueba desde el cliente api

Método http

URL

Código de respuesta

Respuesta

Body

Formato del body

insomnia

CADENA DE conexión a base de datos

<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

datos de conexión: dotenv

// 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

alternativas de conexión a LA BAse de datos

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

ejemplo de conexión a la bd

// 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

modelo de datos: mongoose

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);

crear una tarea: post

// 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);
  }
});

obtener todas las tareas: get

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);
  }
});

obtener una tarea por id: get

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);
    
  }
});

modificar una tarea: Patch

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

eliminar una tarea: delete

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

Cross-Origin Resource Sharing: cors

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

ejemplo de un cliente

Este ejemplo muestra cómo se puede consumir un RestAPI desde Javascript utilizando la librería Axios

ejemplo de un cliente

async/await: instrucciones asíncronas

// 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

cliente nodejs: crear una tarea

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();

cliente nodejs: obtener las tareas

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();

cliente nodejs: obtener una tarea

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');

cliente nodejs: modificar una tarea

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');

cliente nodejs: eliminar una tarea

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');

cliente web: obtener todas las tareas

<!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>

john cardozo

johncardozo@gmail.com

Made with Slides.com