خبر و ترفند روز

خبر و ترفند های روز را اینجا بخوانید!

ساخت یک API ساده با Deno

با یک پروژه مثال عملی با این زمان اجرا JS متمرکز بر امنیت آشنا شوید.

Deno یک زمان اجرا جاوا اسکریپت است که بر روی V8 ساخته شده است، همان موتور جاوا اسکریپت که Google Chrome را تامین می کند. خالق اصلی Node.js Deno را برای رفع برخی از کاستی ها و نگرانی های امنیتی Node.js ایجاد کرد.

اگرچه Deno نسبتا جدید است، اما به عنوان یک زمان اجرا ایمن و مدرن جاوا اسکریپت محبوبیت پیدا کرده است. تمرکز آن بر امنیت، پشتیبانی از ویژگی‌های زبان مدرن و ابزارهای مناسب برای توسعه‌دهندگان، آن را به انتخابی جذاب تبدیل کرده است. می‌توانید از آن برای ساخت برنامه‌های سمت سرور، ابزارهای خط فرمان و سایر پروژه‌های جاوا اسکریپت/تایپ اسکریپت مانند یک API ساده استفاده کنید.

نصب Deno

قبل از اینکه بتوانید از Deno استفاده کنید، باید آن را دانلود و نصب کنید. نصب Deno بسته به سیستم عامل شما متفاوت است.

در macOS و Linux، می توانید Deno را با اجرای این دستور نصب کنید:

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

در ویندوز، می توانید Deno را با Powershell با استفاده از این دستور نصب کنید:

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

با اجرای دستور زیر می توانید تأیید کنید که نصب شما با موفقیت انجام شده است:

deno --version

دستور بالا باید نسخه Deno را در کنسول چاپ کند.

اگر از VS Code به‌عنوان یک IDE استفاده می‌کنید، می‌توانید افزونه Deno’s VS Code را دانلود کنید تا IntelliSense را اضافه کنید و بهره‌وری و تجربه توسعه خود را هنگام کار با پروژه‌های Deno افزایش دهید.

پس از نصب موفقیت آمیز افزونه، یک پوشه .vscode در پوشه ریشه پروژه خود ایجاد کنید و یک فایل settings.json در آن ایجاد کنید.

سپس بلوک کد زیر را به فایل settings.json اضافه کنید تا IntelliSense فعال شود:

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

اتصال به پایگاه داده

برای این آموزش، از MongoDB به عنوان پایگاه داده برای ماندگاری داده ها از API خود استفاده خواهید کرد.

برای اتصال برنامه Deno خود به پایگاه داده MongoDB، یک فایل db.js در فهرست اصلی پروژه خود ایجاد کنید و بلوک کد زیر را به آن اضافه کنید:

// db.js
import { MongoClient } from "https://deno.land/x/mongo@v0.30.1/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");

export default db;

برخلاف Node.js که به مدیران بسته مانند Node Package Manager (npm) یا yarn بستگی دارد، Deno یک سیستم مدیریت بسته داخلی برای وارد کردن و مدیریت وابستگی ها به طور مستقیم از URL ها دارد.

مطلب مرتبط:   نحوه کانتینریزه کردن برنامه های Rust با Docker

به عنوان مثال، بلوک کد بالا MongoClient را از URL https://deno.land/x/mongo@v0.30.1/mod.ts وارد می کند که به بسته منتهی می شود.

سپس، با استفاده از درایور وارداتی Deno MongoDB (MongoClient)، Deno بین برنامه شما و پایگاه داده محلی MongoDB ارتباط برقرار می کند.

در سناریوهای زنده، ذخیره اعتبار پایگاه داده خود در یک فایل env. به جای ذخیره آنها در متن ساده، همانطور که در بالا انجام شد، ایمن تر است.

ایجاد مدل پایگاه داده

در حالی که امکان تعامل با پایگاه داده MongoDB بدون مدل پایگاه داده وجود دارد، انجام این کار می تواند منجر به کدهای غیرساختارمند و کمتر قابل نگهداری شود.

برای جلوگیری از این امر، یک فایل TodoModel.ts در دایرکتوری ریشه پروژه خود ایجاد کنید و با افزودن بلوک کد زیر به فایل، داده های خود را ساختار دهید:

import db from "./db.ts";

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

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

export default Todo;

بلوک کد بالا یک رابط Todo را تعریف می کند که ساختار یک مورد تک کار را نشان می دهد. سپس با استفاده از رابط Todo، یک مجموعه Todo را با فراخوانی متد مجموعه که توسط نمونه MongoDB ایجاد شده قبلی شما در معرض دید قرار گرفته است، ایجاد می کند.

ایجاد سرور با Oak

Oak یک میان افزار برای سرور HTTP بومی Deno است. از Koa الهام گرفته شده است که جایگزینی برای Express.js است.

برای ایجاد یک سرور با Oak، یک فایل main.ts در فهرست اصلی پروژه خود ایجاد کنید و بلوک کد زیر را به فایل خود اضافه کنید.

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

بلوک کد بالا برنامه را از URL Oak وارد می کند و یک نمونه برنامه (برنامه) ایجاد می کند که به ترافیک ورودی در پورت 8000 گوش می دهد.

خط app.use(router.routes()) مسیرهای روتر را به عنوان میان افزار در برنامه Oak ثبت می کند. این بدان معناست که برنامه با مسیرهای ثبت‌شده در برابر درخواست‌های ورودی مطابقت می‌کند و در صورت وجود تطابق، کنترل‌کننده‌های مربوطه اجرا می‌شوند.

مطلب مرتبط:   نحوه نصب Java JDK در ویندوز 11

خط app.use(router.allowedMethods()) روش های HTTP را کنترل می کند که به صراحت در روتر تعریف نشده اند. به عنوان مثال، اگر درخواستی را با یک روش پشتیبانی نشده دریافت کند، به عنوان مثال، یک درخواست PUT ثبت نشده، میان افزار () allowMethods به طور خودکار یک پاسخ مناسب را ارسال می کند (مثلاً 405 Method Not Allowed).

پیاده سازی عملکرد CRUD

این آموزش دارای یک API ساده todo با عملکرد CRUD است.

یک فایل router.ts در دایرکتوری ریشه پروژه خود ایجاد کنید و بلوک کد زیر را به فایل خود اضافه کنید:

import { Router } from "https://deno.land/x/oak/mod.ts";
import Todo from "./todoModel.ts";
import { ObjectId } from "https://deno.land/x/mongo@v0.30.1/mod.ts";

const router = new Router(); // Create Router

بلوک کد بالا نمونه ای از روتر Oak را وارد کرده و ایجاد می کند. با استفاده از این نمونه، می‌توانید با فراخوانی نام متدهای مربوطه (get, post, put, delete) برای روش‌های مختلف HTTP هندلرهای مسیر ایجاد کنید.

به عنوان مثال، بلوک کد زیر نمونه ای از نحوه ایجاد یک کنترل کننده مسیر GET است که تمام اسناد مجموعه Todo شما را برمی گرداند.

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

برای ارسال یک شی پاسخ با استفاده از Deno، باید شی answer.body در RouterContex را به شی پاسخ اختصاص دهید. همین امر در مورد کدهای وضعیت صدق می کند.

برای اضافه کردن سایر کنترل‌کننده‌های مسیر، می‌توانید آنها را به کنترلر مسیر قبلی زنجیره بزنید.

اینطوری:

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

بلوک کد بالا یک کنترل کننده مسیر GET را تعریف می کند که یک مورد Todo را برمی گرداند که با شناسه در پارامترهای URL مطابقت دارد.

در مرحله بعد، یک CREATE route handler تعریف کنید که اسناد جدیدی را به مجموعه شما اضافه می کند:

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

در مرحله بعد، یک کنترل کننده مسیر PUT اضافه کنید که یک Todo را بر اساس پارامتر id با داده های ارسال شده در بدنه درخواست به روز می کند.

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

در نهایت، یک کنترل کننده مسیر DELETE ایجاد کنید که یک Todo را از مجموعه 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",
    };
  });

می توانید برنامه Deno خود را با این دستور شروع کنید:

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

به طور پیش فرض، یک اسکریپت Deno نمی تواند به چیزی خارج از محدوده خود، مانند شبکه یا سیستم فایل دسترسی داشته باشد. بنابراین برای شروع برنامه خود، باید پرچم های مختلفی را برای اعطای مجوزهای لازم به Deno اضافه کنید.

مطلب مرتبط:   نحوه اضافه کردن اشیاء متحرک تصادفی با استفاده از کتابخانه Arcade Python

–allow-net به Deno اجازه می دهد تا درخواست های شبکه را انجام دهد. –allow-read به Deno اجازه دسترسی به سیستم فایل و خواندن فایل ها را می دهد. –allow-env به Deno اجازه می دهد تا به متغیرهای محیطی دسترسی داشته باشد. پرچم –watch برنامه Deno شما را در حالت تماشا راه اندازی می کند.

مهاجرت از Node.js به Deno

مهاجرت از Node.js به Deno برای ساخت API های REST می تواند امنیت، بهره وری توسعه دهندگان و مزایای مدیریت وابستگی را به همراه داشته باشد. با استفاده از زمان اجرا ایمن Deno، پشتیبانی بومی TypeScript و مدیریت وابستگی ساده، می توانید به راحتی API های REST قوی و کارآمد ایجاد کنید.

با این حال، اکوسیستم نابالغ Deno ممکن است باعث شود شما در این مورد تجدید نظر کنید. اگر تصمیم به مهاجرت دارید، جوانب مثبت و منفی را به دقت بسنجید.