【Day 29】Deno + Oak 建立 Restful API (2)

https://ithelp.ithome.com.tw/upload/images/20201014/20109963EeoAMWDT8V.jpg

接续昨天继续实作

还记得我们昨天在 Controller 里新增的 todo.ts ?

export default {
  getAllTodos: () => {},   // 显示 Todo
  createTodo: async () => {},    // 新增 Todo
  getTodoById: () => {},   // 显示单笔 Todo
  updateTodoById: async () => {},  // 修改 Todo
  deleteTodoById: () => {},  // 删除 Todo
}

接下来我们要分别实作这些方法了~~

在开始之前,我们先引入 。。。

// v4 是用於产生 string 型别的 id
import { v4 } from "https://deno.land/std/uuid/mod.ts";
// 引入 Todo 这个介面,约束传递进来的资料
import Todo from "../interfaces/Todo.ts";
// 引入我们 Mock 的假资料
import todos from "../stubs/todos.ts";

显示 Todo

getAllTodos: ({ response }: { response: any }) => {
    response.status = 200;
    response.body = {
      success: true,
      data: todos,  // 搜寻全部,自动带入我们的假资料
    };
  }

这里的 getAllTodos 其实是 getAllTodos: (context) => {},而这里 context 可以有三个变数:

  • request: 使用者发送过来的资料,像是请求或是夹带参数
  • response: 浏览器返回经过 API 後回覆的资料
  • params: 像我们要查询某个 id 的资料,就是从这里带进来的

response.status 代表的是这个API的回覆状态,可能是200(代表成功),也可能是 404(找不到)
response.body 则是 API 的主要回覆资料

显示单笔 Todo

getTodoById: (
    { params, response }: { params: { id: string }; response: any },
  ) => {
    const todo: Todo | undefined = todos.find((t) => {
      return t.id === params.id;
    });
    if (!todo) {
      response.status = 404;
      response.body ={
        success: false,
        message: 'No Todo Found',
      };
      return;
    }

    response.status = 200;
    response.body = {
      success: true,
      data: todo,
    };
  }

这里的 { params: { id: string } 代表带入 id 作为参数去做寻找
const todo 这段是在说将 todo 变数设置为 Todo 类型或是 undefined,它不能是其他类型!!然後用 id 去比对所有的物件,一般取得单笔会去确认此笔单是否存在,存在返回资料与 200 status,不存在返回 404 与 No Todo Found

新增 Todo

createTodo: async (
    { request, response }: { request: any; response: any },
  ) => {
    const body = await request.body();   // 这里返回的是 promise<pending>

    if (!request.hasBody) {
      response.status = 400;
      response.body = { message: "No data provided" };
      return;
    }
    
    const result = await body.value;   // 这里返回的是 string
    const item = JSON.parse(result);
    const newTodo: Todo = {
      id: v4.generate(),
      todo: item.todo,
      isCompleted: false,
    };

    let data = [...todos, newTodo];
    response.body = {
      success: true,
      data,
    };
  }

首先在 const body的部分去读取使用者传递过来的资料,接下来用 oak 内建的 request.hasBody去判断是否传递过来的值是空的,空的就返回 status:400 跟讯息。const result则是去取得 body 内部 value 的值在去 JSON.parse 成物件,这里要注意,否则会出错,变成空值,最後写成 Todo 类型的形式存入我们原先 mock 的资料阵列中并回传。

修改 Todo

updateTodoById: async (
    { params, request, response }: {
      params: { id: string },
      request: any,
      response: any,
    }
  ) => {
    const todo: Todo | undefined = todos.find((t) => t.id === params.id);
    if (!todo) {
      response.status = 404;
      response.body = {
        success: false,
        message: "No todo found",
      };
      return;
    }

    const body = await request.body();
    const result = await body.value;
    const updatedData: { todo?: string; isCompleted?: boolean } = JSON.parse(result);

    let newTodos = todos.map((t) => {
      return t.id === params.id ? { ...t, ...updatedData } : t;
    });

    response.status = 200;
    response.body = {
      success: true,
      data: newTodos,
    };
  }

这里带入 id 来寻找此笔资料更新,跟取得单笔一样,都是先去判断是否存在,因为如果不存在是无法更新的。
{ todo?: string; isCompleted?: boolean },这里将型别的检查添加到 updatedData 上,以及代表的是有可能包含或不包含 todo 跟 isCompleted, 最後将 JSON.parse(result) 赋值给 updatedData,
而 let newTodos 这段则是检查全部当 id 与使用者送进来的 id相同就覆盖过去,最後送出更新後的资料。

删除 Todo

deleteTodoById: (
    { params, response }: { params: { id: string }; response: any },
  ) => {
    const todo: Todo | undefined = todos.find((t) => {
      return t.id === params.id;
    });
    if (!todo) {
      response.status = 404;
      response.body ={
        success: false,
        message: 'No Todo Found',
      };
      return;
    }
    
    const allTodos = todos.filter((t) => t.id !== params.id);
    response.status = 200;
    response.body = {
      success: true,
      data: allTodos,
    }
  }

这里带入 id 来寻找此笔资料删除,跟取得单笔一样,都是先去判断是否存在,因为如果不存在是无法删除的。
比较特别的是,这边是用 filter 去处理,删除掉 todo.id 与 params.id 一样的物件。

参考

Create a Simple REST API with Deno

结论

  • 介绍完整的 oak Restful API

/images/emoticon/emoticon06.gif


<<:  【Day 28】Deno + Oak 建立 Restful API (1)

>>:  【Day 30】铁人赛後心得

Day21:[排序演算法]Heap Sort - 堆积排序法

heap sort的原理是采用max heap这种资料结构来做排序,max heap是一种bina...

Day 06 Flex message simulator- 美化自己的chatbot

Flex message simulator- 美化自己的chatbot 虽然已经能让 Line c...

前端工程学习日记第17天

#伪类:before :after做左右画线标题效果 经常可以看到这样的标题设计是在左右有一条横线中...

SCSS

使用SCSS取代CSS更易於阅读,巢状的写法、提供的功能像变数、mixin、function、imp...

[Day13]ISO 27001 标准:风险评监

风险 表示发生,可能会对价值或资产造成负面的冲击。 风险是外部威胁利用弱点对内部资产造成冲击的可能性...