Scopri questo runtime JS incentrato sulla sicurezza con un progetto di esempio pratico.

Deno è un runtime JavaScript basato su V8, lo stesso motore JavaScript che alimenta Google Chrome. Il creatore originale di Node.js ha creato Deno per affrontare alcune delle carenze e dei problemi di sicurezza di Node.js.

Sebbene sia relativamente nuovo, Deno ha guadagnato popolarità come runtime JavaScript sicuro e moderno. La sua attenzione alla sicurezza, il supporto per le funzionalità del linguaggio moderno e gli strumenti adatti agli sviluppatori lo rendono una scelta interessante. Puoi usarlo per creare applicazioni lato server, strumenti da riga di comando e altri progetti JavaScript/TypeScript, come una semplice API.

Installazione di Deno

Prima di poter utilizzare Deno devi scaricarlo e installarlo. L'installazione di Deno varia a seconda del sistema operativo.

Su macOS e Linux, puoi installare Deno eseguendo questo comando:

curl -fsSL https://deno.land/x/install/install.sh | sh

Su Windows, puoi installare Deno con Powershell, usando questo comando:

instagram viewer
irm https://deno.land/install.ps1 | iex

Puoi confermare che l'installazione è andata a buon fine eseguendo il comando seguente:

deno --version

Il comando sopra dovrebbe stampare la versione Deno sulla console.

Se usi VS Code come IDE, puoi scaricare Estensione VS Code di Deno per aggiungere IntelliSense, migliorando la produttività e l'esperienza di sviluppo quando si lavora con i progetti Deno.

Dopo aver installato correttamente l'estensione, creare un file .vscode cartella nella directory principale del tuo progetto e crea un file settings.json file in esso.

Quindi, aggiungi il blocco di codice qui sotto al file settings.json file per abilitare IntelliSense:

{
"deno.enable": true,
"deno.unstable": true,
}

Connessione a un database

Per questo tutorial, utilizzerai MongoDB come database per persistere i dati dalla tua API.

Per connettere la tua app Deno a un database MongoDB, crea un file db.js file nella directory principale del progetto e aggiungi il blocco di codice seguente:

// 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 differenza di Node.js, che dipende da gestori di pacchetti come il Node Package Manager (npm) o il filato, Deno ha un sistema di gestione dei pacchetti integrato per l'importazione e la gestione delle dipendenze direttamente dagli URL.

Ad esempio, il blocco di codice sopra imports MongoClient dall'URL https://deno.land/x/[email protected]/mod.ts, che porta al pacchetto.

Quindi, utilizzando il driver Deno MongoDB importato (MongoClient), Deno stabilisce una connessione tra la tua applicazione e un database MongoDB locale.

Negli scenari live, è più sicuro archiviare le credenziali del database in un file .env file invece di memorizzarli in testo normale, come fatto sopra.

Creazione di un modello di database

Mentre è possibile interagire con un database MongoDB senza un modello di database, farlo può portare a codice non strutturato e meno gestibile.

Per evitare ciò, crea un file TodoModel.ts file nella directory principale del tuo progetto e struttura i tuoi dati aggiungendo il blocco di codice seguente al file:

import db from"./db.ts";

interface Todo {
title: string;
description: string;
completed?: boolean;
}

const Todo = db.collection("todos");

exportdefault Todo;

Il blocco di codice sopra definisce un'interfaccia Fare che rappresenta la struttura di un singolo elemento todo. Quindi, utilizzando l'interfaccia Todo, crea una raccolta Todo chiamando il metodo di raccolta esposto dall'istanza MongoDB creata in precedenza.

Creazione di un server con Oak

Oak è un middleware per il server HTTP nativo di Deno. È stato ispirato da Koa, che è un alternativa a Express.js.

Per creare un server con Oak, crea un file main.ts file nella directory principale del progetto e aggiungi il blocco di codice riportato di seguito al tuo file.

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

Il blocco di codice sopra importa Applicazione dall'URL Oak e crea un'istanza dell'applicazione (app) che ascolta il traffico in entrata sulla porta 8000.

IL app.use (router.routes()) line registra i percorsi del router come middleware nell'applicazione Oak. Ciò significa che l'applicazione corrisponderà alle route registrate rispetto alle richieste in entrata e i gestori corrispondenti verranno eseguiti se esiste una corrispondenza.

IL app.use (router.allowedMethods()) line gestisce i metodi HTTP che non sono definiti esplicitamente nel router. Ad esempio, se riceve una richiesta con un metodo non supportato, ad esempio una richiesta PUT non registrata, il metodi consentiti() il middleware invierà automaticamente una risposta appropriata (ad esempio, 405 Metodo non consentito).

Implementazione della funzionalità CRUD

Questo tutorial presenterà una semplice API todo con funzionalità CRUD.

Creare un router.ts file nella directory principale del tuo progetto e aggiungi il blocco di codice seguente al tuo file:

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

Il blocco di codice sopra importa e crea un'istanza del router Oak. Utilizzando questa istanza, puoi creare gestori di route per vari metodi HTTP chiamando i rispettivi nomi di metodo (Ottenere, inviare, Mettere, eliminare).

Ad esempio, il blocco di codice seguente è un esempio di come puoi creare un gestore di instradamento GET che restituisce tutti i documenti nella tua raccolta Todo.

router
.get("/api/todos", (ctx: RouterContextapi/todos">) => {
ctx.response.body = Todo.find();
})

Per inviare un oggetto risposta utilizzando Deno, è necessario assegnare il risposta.corpo oggetto su RouterContex all'oggetto risposta. Lo stesso vale per i codici di stato.

Per aggiungere altri gestori di instradamento, puoi concatenarli al gestore di instradamento precedente.

Così:

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

Il blocco di codice sopra definisce un gestore di route GET che restituisce un singolo elemento Todo che corrisponde all'id nei parametri dell'URL.

Successivamente, definisci un gestore di route CREATE che aggiunge nuovi documenti alla tua raccolta:

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

Successivamente, aggiungi un gestore di route PUT che aggiorni un Todo basato su id parametro, con i dati inviati nel corpo della richiesta.

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

Infine, crea un gestore di route DELETE che rimuove un Todo dalla tua raccolta 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",
};
});

Puoi avviare la tua app Deno con questo comando:

deno run --allow-net --allow-read --allow-env --watch main.ts

Per impostazione predefinita, uno script Deno non può accedere a nulla al di fuori del suo ambito, come la rete o il file system. Quindi, per avviare la tua applicazione, devi includere vari flag per concedere a Deno le autorizzazioni richieste.

--allow-net consente a Deno di effettuare richieste di rete. --allow-read consente a Deno di accedere al file system e leggere i file. --allow-env consente a Deno di accedere alle variabili ambientali. IL --orologio flag avvia la tua app Deno in modalità orologio.

Migrazione da Node.js a Deno

La migrazione da Node.js a Deno per la creazione di API REST può portare significativi vantaggi in termini di sicurezza, produttività degli sviluppatori e gestione delle dipendenze. Utilizzando il runtime sicuro di Deno, il supporto nativo di TypeScript e la gestione semplificata delle dipendenze, puoi creare facilmente API REST solide ed efficienti.

Tuttavia, l'ecosistema immaturo di Deno potrebbe farti riconsiderare. Se scegli di migrare, valuta attentamente i pro e i contro.