Cunoașteți acest runtime JS axat pe securitate cu un exemplu de proiect practic.
Deno este un runtime JavaScript construit pe V8, același motor JavaScript care alimentează Google Chrome. Creatorul original al Node.js a creat Deno pentru a rezolva unele dintre deficiențele și preocupările de securitate ale Node.js.
Deși este relativ nou, Deno a câștigat popularitate ca runtime JavaScript sigur și modern. Accentul său pe securitate, suport pentru caracteristicile limbajului modern și instrumentele prietenoase pentru dezvoltatori îl fac o alegere atrăgătoare. Îl puteți folosi pentru a construi aplicații pe partea de server, instrumente de linie de comandă și alte proiecte JavaScript/TypeScript, ca un simplu API.
Instalarea Deno
Înainte de a putea folosi Deno, trebuie să îl descărcați și să îl instalați. Instalarea lui Deno variază în funcție de sistemul dvs. de operare.
Pe macOS și Linux, puteți instala Deno rulând această comandă:
curl -fsSL https://deno.land/x/install/install.sh | sh
Pe Windows, puteți instala Deno cu Powershell, folosind această comandă:
irm https://deno.land/install.ps1 | iex
Puteți confirma că instalarea a avut succes executând comanda de mai jos:
deno --version
Comanda de mai sus ar trebui să imprime versiunea Deno pe consolă.
Dacă utilizați VS Code ca IDE, puteți descărca Extensia VS Code a lui Deno pentru a adăuga IntelliSense, îmbunătățindu-vă productivitatea și experiența de dezvoltare atunci când lucrați cu proiecte Deno.
După instalarea cu succes a extensiei, creați un .vscode folder în directorul rădăcină al proiectului și creați un settings.json dosar în el.
Apoi, adăugați blocul de cod de mai jos la settings.json fișier pentru a activa IntelliSense:
{
"deno.enable": true,
"deno.unstable": true,
}
Conectarea la o bază de date
Pentru acest tutorial, veți folosi MongoDB ca bază de date pentru a persista datele din API-ul dvs.
Pentru a vă conecta aplicația Deno la o bază de date MongoDB, creați un db.js fișier în directorul rădăcină al proiectului și adăugați blocul de cod de mai jos la acesta:
// 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;
Spre deosebire de Node.js, care depinde de managerii de pachete precum Node Package Manager (npm) sau yarn, Deno are un sistem de gestionare a pachetelor încorporat pentru importarea și gestionarea dependențelor direct din URL-uri.
De exemplu, blocul de cod de mai sus importă MongoClient de la adresa URL https://deno.land/x/[email protected]/mod.ts, care duce la pachet.
Apoi, folosind driverul Deno MongoDB importat (MongoClient), Deno stabilește o conexiune între aplicația dvs. și o bază de date locală MongoDB.
În scenariile live, este mai sigur să stocați acreditările bazei de date într-un .env fișier în loc să le stocați în text simplu, așa cum s-a făcut mai sus.
Crearea unui model de bază de date
În timp ce este posibil să interacționează cu o bază de date MongoDB fără un model de bază de date, acest lucru poate duce la cod nestructurat și mai puțin întreținut.
Pentru a evita acest lucru, creați un TodoModel.ts fișier în directorul rădăcină al proiectului și structurați-vă datele adăugând blocul de cod de mai jos la fișier:
import db from"./db.ts";
interface Todo {
title: string;
description: string;
completed?: boolean;
}const Todo = db.collection
("todos");
exportdefault Todo;
Blocul de cod de mai sus definește o interfață A face care reprezintă structura unui singur articol tot. Apoi, folosind interfața Todo, creează o colecție Todo apelând metoda de colectare expusă de instanța MongoDB creată anterior.
Crearea unui server cu stejar
Oak este un middleware pentru serverul HTTP nativ al Deno. A fost inspirat de Koa, care este un alternativă la Express.js.
Pentru a crea un server cu Oak, creați un principale.ts fișier în directorul rădăcină al proiectului și adăugați blocul de cod de mai jos la fișier.
// 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");
Blocul de cod de mai sus importă Aplicație din URL-ul Oak și creează o instanță de aplicație (aplicația) care ascultă traficul de intrare pe portul 8000.
The app.use (router.routes()) line înregistrează rutele routerului ca middleware în aplicația Oak. Aceasta înseamnă că aplicația va potrivi rutele înregistrate cu cererile primite, iar handler-urile corespunzătoare vor rula dacă există o potrivire.
The app.use (router.allowedMethods()) line tratează metode HTTP care nu sunt definite în mod explicit în router. De exemplu, dacă primește o solicitare cu o metodă neacceptată, de exemplu, o solicitare PUT neînregistrată, PermisMethods() middleware-ul va trimite automat un răspuns adecvat (de ex., 405 Metoda nu este permisă).
Implementarea funcționalității CRUD
Acest tutorial va prezenta un simplu API todo cu funcționalitate CRUD.
Creeaza o router.ts fișier în directorul rădăcină al proiectului și adăugați blocul de cod de mai jos la fișierul dvs.:
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
Blocul de cod de mai sus importă și creează o instanță a routerului Oak. Folosind această instanță, puteți crea gestionari de rută pentru diferite metode HTTP apelând numele metodelor respective (obține, post, a pune, șterge).
De exemplu, blocul de cod de mai jos este un exemplu despre cum puteți crea un handler de rută GET care returnează toate documentele din colecția ta Todo.
router
.get("/api/todos", (ctx: RouterContextapi/todos">) => {
ctx.response.body = Todo.find();
})
Pentru a trimite un obiect de răspuns folosind Deno, trebuie să atribuiți răspuns.corp obiect de pe RouterContex la obiectul de răspuns. Același lucru este valabil și pentru codurile de stare.
Pentru a adăuga alți operatori de rută, îi puteți înlănțui la gestionarea de rută anterior.
Ca astfel:
.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,
};
}
})
Blocul de cod de mai sus definește un handler de rută GET care returnează un singur element Todo care se potrivește cu id-ul din parametrii URL.
Apoi, definiți un handler de rută CREATE care adaugă noi documente la colecția dvs.:
.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,
};
}
})
Apoi, adăugați un handler de rută PUT care actualizează un Todo pe baza id parametru, cu datele trimise în corpul cererii.
.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,
};
}
})
În cele din urmă, creați un handler de rută DELETE care elimină un Todo din colecția dvs. 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",
};
});
Puteți porni aplicația Deno cu această comandă:
deno run --allow-net --allow-read --allow-env --watch main.ts
În mod implicit, un script Deno nu poate accesa nimic în afara domeniului său de aplicare, cum ar fi rețeaua sau sistemul de fișiere. Așadar, pentru a începe aplicația, trebuie să includeți diferite steaguri pentru a acorda lui Deno permisiunile necesare.
--permite-net permite lui Deno să facă cereri de rețea. --permite-citire permite lui Deno să acceseze sistemul de fișiere și să citească fișiere. --allow-env permite lui Deno să acceseze variabilele de mediu. The --ceas flag pornește aplicația Deno în modul ceas.
Migrarea de la Node.js la Deno
Migrarea de la Node.js la Deno pentru construirea de API-uri REST poate aduce beneficii semnificative de securitate, productivitate dezvoltatorului și management al dependenței. Folosind timpul de rulare securizat al Deno, suportul nativ TypeScript și gestionarea simplificată a dependenței, puteți crea cu ușurință API-uri REST robuste și eficiente.
Cu toate acestea, ecosistemul imatur al lui Deno vă poate determina să vă reconsiderați. Dacă alegeți să migrați, cântăriți cu atenție argumentele pro și contra.