Cách xây dựng API đơn giản bằng Deno

Deno là một runtime JavaScript được tích hợp trên V8, , cùng một công cụ JavaScript cung cấp năng lượng cho Google Chrome. Bạn có thể dùng Deno để xây dựng một API đơn giản.

Deno

Cài đặt Deno

Đầu tiên, bạn phải download và cài đặt nó. Bản cài của Deno thay đổi theo hệ điều hành.

Trên macOS & Linux, chạy lệnh cài:

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

Trên Windows, bạn có thể cài Deno bằng Powershell:

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

Xác nhận cài đặt thành công bằng cách chạy lệnh sau:

deno --version

Kết nối database

Ở hướng dẫn này, bạn sẽ dùng MongoDB làm database để duy trì dữ liệu từ API.

Để kết nối app Deno với database MongoDB, tạo file db.js trong thư mục gốc của dự án và thêm khối code này bên dưới nó:

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

Deno có một hệ thống quản lý package riêng cho việc nhập và quản lý trực tiếp các phần phụ thuộc từ URL.

Ví dụ, khối code trên nhập MongoClient từ URL: https://deno.land/x/mongo@v0.30.1/mod.ts dẫn tới package này.

Sau đó, dùng driver Deno MongoDB đã nhập (MongoClient), Deno thiết lập một kết nối giữa ứng dụng và database MongoDB cục bộ.

Tạo mẫu database

Dù có thể tương tác với database MongoDB mà không cần tới mẫu database, làm việc này có thể dẫn tới code lộn xộn và ít có khả năng bảo trì.

Để tránh điều đó, tạo file TodoModel.ts trong thư mục gốc của dự án và lên cấu trúc dữ liệu bằng cách thêm khối code bên dưới vào file:

import db from "./db.ts";
 
interface Todo {
  title: string;
  description: string;
  completed?: boolean;
}
 
const Todo = db.collection("todos");
 
export default Todo;

Khối code trên định nghĩa một interface Todo đại diện cho cấu trúc của một mục công việc đơn lẻ. Sau đó, sử dụng giao diện Todo, nó tạo một bộ sưu tập Todo bằng cách gọi phương thức bộ sưu tập được hiển thị bằng phiên bản MongoDB đã tạo trước đó của bạn.

Tạo server với Oak

Oak là phần mềm trung gian cho máy chủ HTTP gốc của Deno. Nó được lấy cảm hứng từ Koa, một giải pháp thay thế cho Express.js.

Để tạo một máy chủ với Oak, hãy tạo một tệp main.ts trong thư mục gốc của dự án và thêm khối mã bên dưới vào tệp của bạn.

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

Khối code trên nhập Application từ URL Oak và tạo một phiên bản ứng dụng (app) lắng nghe lưu lượng truy cập đến trên cổng 8000.

Dòng app.use(router.routes()) đăng ký các tuyến của bộ định tuyến dưới dạng phần mềm trung gian trong ứng dụng Oak. Điều này có nghĩa là ứng dụng sẽ khớp các tuyến đã đăng ký với các yêu cầu đến và các trình xử lý tương ứng sẽ chạy nếu có kết quả trùng khớp.

Dòng app.use(router.allowedMethods()) xử lý các phương thức HTTP không được xác định rõ ràng trong bộ định tuyến. Ví dụ: nếu nó nhận được yêu cầu có phương thức không được hỗ trợ, chẳng hạn như yêu cầu PUT chưa đăng ký, middleware allowMethods() sẽ tự động gửi phản hồi thích hợp (ví dụ: 405 Method Not Allowed).

Triển khai tính năng CRUD

Hướng dẫn này xe bao gồm một API todo đơn giản với tính năng CRUD.

Tạo tệp router.ts trong thư mục gốc của dự án và thêm khối mã bên dưới vào tệp của bạn:

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

Khối code trên nhập và tạo một phiên bản của bộ định tuyến Oak. Sử dụng ví dụ này, bạn có thể tạo các trình xử lý định tuyến cho các phương thức HTTP khác nhau bằng cách gọi các tên phương thức tương ứng (get, post, put, delete).

Ví dụ: khối code bên dưới là một ví dụ về cách bạn có thể tạo trình xử lý tuyến đường GET trả về tất cả các tài liệu trong bộ sưu tập Todo của bạn.

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

Để gửi một đối tượng phản hồi bằng Deno, bạn phải gán đối tượng response.body trên RouterContex cho đối tượng phản hồi. Điều tương tự cũng áp dụng cho code trạng thái.

Để thêm trình xử lý lộ trình khác, bạn có thể xâu chuỗi chúng sang trình xử lý route trước đó.

Ví dụ:

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

Khối code trên xác định trình xử lý route GET trả về một mục Todo duy nhất khớp với id trong thông số URL.

Tiếp theo, xác định trình route CREATE để thêm tài liệu mới vào bộ sưu tập của bạ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,
      };
    }
  })

Tiếp theo, thêm trình xử lý route PUT cập nhật Todo dựa trên tham số id, với dữ liệu được gửi trong phần thân yêu cầu.

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

Cuối cùng, tạo trình xử lý route DELETE loại bỏ một Todo từ bộ sưu tập 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",
    };
  });

Giờ khởi động app Deno bằng lệnh này:

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

Chúc các bạn thành công!

Chủ Nhật, 20/08/2023 05:33
41 👨 189
0 Bình luận
Sắp xếp theo