Conozca este tiempo de ejecución de JS centrado en la seguridad con un proyecto de ejemplo práctico.
Deno es un tiempo de ejecución de JavaScript basado en V8, el mismo motor de JavaScript que impulsa Google Chrome. El creador original de Node.js creó Deno para abordar algunas de las deficiencias y preocupaciones de seguridad de Node.js.
Aunque es relativamente nuevo, Deno ha ganado popularidad como un tiempo de ejecución de JavaScript seguro y moderno. Su enfoque en la seguridad, el soporte para funciones de lenguaje moderno y las herramientas fáciles de usar para desarrolladores lo convierten en una opción atractiva. Puede usarlo para crear aplicaciones del lado del servidor, herramientas de línea de comandos y otros proyectos de JavaScript/TypeScript, como una API simple.
Instalación de Deno
Antes de poder usar Deno, debe descargarlo e instalarlo. La instalación de Deno varía según su sistema operativo.
En macOS y Linux, puede instalar Deno ejecutando este comando:
curl -fsSL https://deno.land/x/install/install.sh | sh
En Windows, puede instalar Deno con Powershell, usando este comando:
irm https://deno.land/install.ps1 | iex
Puede confirmar que su instalación fue exitosa ejecutando el siguiente comando:
deno --version
El comando anterior debería imprimir la versión de Deno en la consola.
Si usa VS Code como IDE, puede descargar Extensión VS Code de Deno para agregar IntelliSense, mejorando su productividad y experiencia de desarrollo cuando trabaja con proyectos de Deno.
Después de instalar con éxito la extensión, cree una .vscode carpeta en el directorio raíz de su proyecto y cree una configuración.json archivo en él.
A continuación, agregue el bloque de código a continuación al configuración.json archivo para habilitar IntelliSense:
{
"deno.enable": true,
"deno.unstable": true,
}
Conexión a una base de datos
Para este tutorial, utilizará MongoDB como base de datos para conservar los datos de su API.
Para conectar su aplicación Deno a una base de datos MongoDB, cree una db.js archivo en el directorio raíz de su proyecto y agregue el bloque de código a continuación:
// db.js
import { MongoClient } from"https://deno.land/x/[email protected]/mod.ts";const client = new MongoClient();
try {
await client.connect("mongodb://localhost: 27017/todo");console.log("Connected to database");
} catch (err) {
console.log("Error connecting to database", err);
}const db = client.database("todo");
exportdefault db;
A diferencia de Node.js, que depende de administradores de paquetes Al igual que Node Package Manager (npm) o yarn, Deno tiene un sistema de administración de paquetes incorporado para importar y administrar dependencias directamente desde URL.
Por ejemplo, el bloque de código anterior importa MongoCliente de la URL https://deno.land/x/[email protected]/mod.ts, que conduce al paquete.
Luego, usando el controlador Deno MongoDB importado (MongoCliente), Deno establece una conexión entre su aplicación y una base de datos MongoDB local.
En escenarios reales, es más seguro almacenar las credenciales de su base de datos en un .env archivo en lugar de almacenarlos en texto sin formato, como se hizo anteriormente.
Creación de un modelo de base de datos
Si bien es posible interactuar con una base de datos MongoDB sin un modelo de base de datos, hacerlo puede conducir a un código desestructurado y menos mantenible.
Para evitar esto, crea un TodoModel.ts en el directorio raíz de su proyecto y estructure sus datos agregando el siguiente bloque de código al archivo:
import db from"./db.ts";
interface Todo {
title: string;
description: string;
completed?: boolean;
}const Todo = db.collection
("todos");
exportdefault Todo;
El bloque de código anterior define una interfaz Hacer que representa la estructura de un único elemento de tareas pendientes. Luego, usando la interfaz de Todo, crea una colección de Todo llamando al método de colección expuesto por su instancia de MongoDB creada previamente.
Crear un servidor con Oak
Oak es un middleware para el servidor HTTP nativo de Deno. Se inspiró en Koa, que es un alternativa a Express.js.
Para crear un servidor con Oak, cree un principal.ts archivo en el directorio raíz de su proyecto y agregue el bloque de código a continuación a su archivo.
// main.ts
import { Application } from"https://deno.land/x/oak/mod.ts";
import router from"./router.ts";const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());
await app.listen({ port: 8000 });
console.log("Server running on port 8000");
El bloque de código sobre las importaciones Solicitud de la URL de Oak y crea una instancia de aplicación (aplicación) que escucha el tráfico entrante en el puerto 8000.
El app.use (router.routes()) line registra las rutas del enrutador como middleware en la aplicación Oak. Esto significa que la aplicación comparará las rutas registradas con las solicitudes entrantes y los controladores correspondientes se ejecutarán si existe una coincidencia.
El app.use (router.allowedMethods()) line maneja los métodos HTTP que no están definidos explícitamente en el enrutador. Por ejemplo, si recibe una solicitud con un método no admitido, por ejemplo, una solicitud PUT no registrada, el métodos permitidos() el middleware enviará automáticamente una respuesta apropiada (por ejemplo, 405 Método no permitido).
Implementación de la funcionalidad CRUD
Este tutorial contará con una API de tareas simples con funcionalidad CRUD.
Crear un enrutador.ts archivo en el directorio raíz de su proyecto y agregue el siguiente bloque de código a su archivo:
import { Router } from"https://deno.land/x/oak/mod.ts";
import Todo from"./todoModel.ts";
import { ObjectId } from"https://deno.land/x/[email protected]/mod.ts";
const router = new Router(); // Create Router
El bloque de código anterior importa y crea una instancia del enrutador Oak. Con esta instancia, puede crear controladores de ruta para varios métodos HTTP llamando a los nombres de los métodos respectivos (conseguir, correo, poner, borrar).
Por ejemplo, el bloque de código a continuación es un ejemplo de cómo puede crear un controlador de ruta GET que devuelva todos los documentos en su colección Todo.
router
.get("/api/todos", (ctx: RouterContextapi/todos">) => {
ctx.response.body = Todo.find();
})
Para enviar un objeto de respuesta usando Deno, debe asignar el respuesta.cuerpo objeto en el RouterContex al objeto de respuesta. Lo mismo se aplica a los códigos de estado.
Para agregar otros controladores de ruta, puede encadenarlos al controlador de ruta anterior.
Al igual que:
.get("/api/todo/:id", async (ctx: RouterContext<"/api/todo/:id">) => {
try {
const todo = await Todo.findOne({ _id: new ObjectId(ctx.params.id) });if (!todo) {
ctx.response.status = 404;ctx.response.body = {
msg: "Todo not found",
};return;
}ctx.response.body = todo;
} catch (error) {
ctx.response.status = 500;
ctx.response.body = {
msg: "Error getting todo",
error,
};
}
})
El bloque de código anterior define un controlador de ruta GET que devuelve un solo elemento Todo que coincide con la identificación en los parámetros de URL.
A continuación, defina un controlador de ruta CREATE que agregue nuevos documentos a su colección:
.post("/api/todo/new", async (ctx: RouterContext<"/api/todo/new">) => {
const body = ctx.request.body();
const todo = await body.value;if (!todo) {
ctx.response.status = 400;
ctx.response.body = { msg: "Invalid data. Please provide a valid todo." };
return;
}const { title, description } = todo;
if (!(title && description)) {
ctx.response.status = 400;ctx.response.body = {
msg: "Title or description missing. Please provide a valid todo.",
};return;
}try {
await Todo.insertOne({
title: todo.title,
description: todo.description,
completed: false,
});ctx.response.status = 201;
ctx.response.body = {
msg: "Todo added successfully",
};
} catch (error) {
ctx.response.status = 500;
ctx.response.body = {
msg: "Error adding todo",
error,
};
}
})
A continuación, agregue un controlador de ruta PUT que actualice un Todo según el identificación parámetro, con los datos enviados en el cuerpo de la solicitud.
.put("/api/todo/:id", async (ctx: RouterContext<"/api/todo/:id">) => {
try {
const body = ctx.request.body();
const todo = await body.value;await Todo.updateOne(
{ _id: new ObjectId(ctx.params.id) },
{ $set: { title: todo.title, description: todo.description } }
);ctx.response.status = 200;
ctx.response.body = {
msg: "Todo updated successfully",
};
} catch (error) {
console.log(error);
ctx.response.status = 500;
ctx.response.body = {
msg: "Error updating todo",
error: error.message,
};
}
})
Finalmente, cree un controlador de ruta DELETE que elimine un Todo de su colección MongoDB:
.delete("/api/todo/:id", async (ctx: RouterContext<"/api/todo/:id">) => {
await Todo.deleteOne({ _id: new ObjectId(ctx.params.id) });ctx.response.status = 200;
ctx.response.body = {
msg: "Todo deleted successfully",
};
});
Puede iniciar su aplicación Deno con este comando:
deno run --allow-net --allow-read --allow-env --watch main.ts
De forma predeterminada, un script de Deno no puede acceder a nada fuera de su alcance, como la red o el sistema de archivos. Entonces, para iniciar su aplicación, debe incluir varias banderas para otorgar a Deno los permisos requeridos.
--permitir-net permite a Deno realizar solicitudes de red. --permitir-leer permite a Deno acceder al sistema de archivos y leer archivos. --permitir-env permite a Deno acceder a variables ambientales. El --mirar flag inicia su aplicación Deno en modo reloj.
Migración de Node.js a Deno
La migración de Node.js a Deno para crear API REST puede brindar importantes beneficios de seguridad, productividad del desarrollador y administración de dependencias. Con el tiempo de ejecución seguro de Deno, la compatibilidad nativa con TypeScript y la administración de dependencias simplificada, puede crear fácilmente API REST sólidas y eficientes.
Sin embargo, el ecosistema inmaduro de Deno puede hacer que lo reconsideres. Si decide migrar, evalúe cuidadosamente los pros y los contras.