原文地址:Create a server with deno and mongo[1]node
原文做者:Kailas Walldoddigit
译者:Tony.Xugithub
读完这篇文章,你应该能够掌握:web
deno_mongo
操做
mongodb
数据库
CRUD
API 来管理员工信息
Controller
)
abc
denv
建立环境变量
首先,安装 deno
。能够查阅这篇文档[2],根据当前系统来选择合适的命令行进行安装。mongodb
PS: 截止做者(Kailas Walldoddi)写这篇文章时,deno
版本是 1.0.0
。typescript
PSS:截止译者(Tony.Xu)写这篇译文和运行样例时,
deno
版本是1.1.1
,deno_mongo
版本是0.8.0
,推荐参考掘金上韩亦乐大佬这篇文章进行安装:Deno 钻研之术:(1) Hello,从多样化安装到简单实战[3]。数据库友情提示:目前 Mac 用户使用 homebrew 安装版本只有
0.4.2
,运行本文章代码会报错express本文最后附 Mac 安装
1.1.1
版本deno
的命令json
为了实现咱们为服务器设计的功能,咱们须要一个框架
(相似 Node.js
中的 express
)。在这里,咱们使用 abc
这个简易的 deno
框架来建立 web
应用(除了 abc
,你还有不少其余选择,好比:alosaur
、espresso
、fen
、oak
…… )api
首先,咱们在项目根目录下新建 .env
文件,用来声明环境变量。
DB_NAME=deno_demo DB_HOST_URL=mongodb://localhost:27017 复制代码
接着,构建异常处理中间件来处理控制器中捕获的报错。utils/middleware.ts
// utils/middleware.ts
import { MiddlewareFunc } from "https://deno.land/x/abc@v1.0.0-rc2/mod.ts"; export class ErrorHandler extends Error { status: number; constructor(message: string, status: number) { super(message); this.status = status; } } export const ErrorMiddleware: MiddlewareFunc = (next: any) => async (c: any) => { try { await next(c); } catch (err) { const error = err as ErrorHandler; c.response.status = error.status || 500; c.response.body = error.message; } }; 复制代码
而后,编写服务器主程序。server.ts
// server.ts
// 经过 url 直接引入远程模块。首次运行后,deno 会下载并缓存该模块 import { Application } from "https://deno.land/x/abc@v1.0.0-rc2/mod.ts"; // 使用 denv 来加载 .env 中配置的环境变量 import "https://deno.land/x/denv/mod.ts"; // 余下代码和 `express` 几乎同样,没什么特别的。 import { fetchAllEmployees, createEmployee, fetchOneEmployee, updateEmployee, deleteEmployee, } from "./controllers/employees.ts"; import { ErrorMiddleware } from "./utils/middlewares.ts"; const app = new Application(); app.use(ErrorMiddleware); app.get("/employees", fetchAllEmployees) .post("/employees", createEmployee) .get("/employees/:id", fetchOneEmployee) .put("/employees/:id", updateEmployee) .delete("/employees/:id", deleteEmployee) .start({ port: 5000 }); console.log(`server listening on http://localhost:5000`); 复制代码
代码第一行,经过 url 直接引入远程模块。首次运行后,deno
会下载并缓存该模块。
代码第二行,使用 denv
来加载 .env
中配置的环境变量。
余下代码和 express
几乎同样,没什么特别的。
接下来咱们要为服务器配置 mongodb
链接。幸运的是,已经有现成的 deno
版本的 MongoDB
驱动:deno_mongo
。虽然目前 deno_mongo
仍在开发中,而且还未涵盖 mongodb
驱动的所有方法,不过用来作一个小 demo
仍是 OK 的。
在 config/
目录下新建 db.ts
文件
// /config/db.ts
// 注:原文版本 deno_mongo 0.6.0,与 deno 1.1.1 不兼容,须要升级到 0.8.0 import { init, MongoClient } from "https://deno.land/x/mongo@v0.8.0/mod.ts"; // 注:原文建立 db 实例的操做有点复杂…… 如下参照了 deno_mongo 官方文档 // https://github.com/manyuanrong/deno_mongo/tree/master // db 名称 const dbName = Deno.env.get("DB_NAME") || "deno_demo"; // db url const dbHostUrl = Deno.env.get("DB_HOST_URL") || "mongodb://localhost:27017"; // 建立链接 const client = new MongoClient(); // 创建链接 client.connectWithUri(dbHostUrl); const db = client.database(dbName); export default db; 复制代码
接下来,编写控制器,先重新建员工 createEmployee
开始
// /controllers/employee.ts
import { HandlerFunc, Context } from "https://deno.land/x/abc@v1.0.0-rc2/mod.ts"; import db from '../config/db.ts'; import { ErrorHandler } from "../utils/middlewares.ts"; const employees = db.collection('employees'); // 定义 schema interface Employee { _id: { $oid: string; }; name: string; age: number; salary: number; } /** * 新增员工 * @param c Context * @returns $oid 目前 deno_mongo 新增时只返回 _id */ export const createEmployee: HandlerFunc = async (c: Context) => { try { if (c.request.headers.get("content-type") !== "application/json") { throw new ErrorHandler("Invalid body", 422); } const body = await (c.body()); if (!Object.keys(body).length) { throw new ErrorHandler("Request body can not be empty!", 400); } const { name, salary, age } = body; const insertedEmployee = await employees.insertOne({ name, age, salary, }); return c.json(insertedEmployee, 201); } catch (error) { throw new ErrorHandler(error.message, error.status || 500); } }; 复制代码
目前 deno_mongo
新增时只返回 _id
(但愿后续版本会改进这一点)
请求:
返回:
查询所有员工:fetchAllEmployees
/** * 全量查询 * @param c Context * @returns json(Employee[]) */ export const fetchAllEmployees: HandlerFunc = async (c: Context) => { try { const fetchedEmployees: Employee[] = await employees.find(); if (fetchedEmployees) { const list = fetchedEmployees.length ? fetchedEmployees.map((employee) => { const { _id: { $oid }, name, age, salary } = employee; return { id: $oid, name, age, salary }; }) : []; return c.json(list, 200); } } catch (error) { throw new ErrorHandler(error.message, error.status || 500); } }; 复制代码
指定 id
查询员工:fetchOneEmployee
/** * 指定 id 查询 * @param c Context * @returns json(Employee) */ export const fetchOneEmployee: HandlerFunc = async (c: Context) => { try { const { id } = c.params as { id: string }; const fetchedEmployee = await employees.findOne({ _id: { "$oid": id } }); if (fetchedEmployee) { const { _id: { $oid }, name, age, salary } = fetchedEmployee; return c.json({ id: $oid, name, age, salary }, 200); } throw new ErrorHandler("Employee not found", 404); } catch (error) { throw new ErrorHandler(error.message, error.status || 500); } }; 复制代码
请求:
返回:
更新员工信息: updateEmployee
/**
* 更新员工 * @param c Context * @returns msg string */ export const updateEmployee: HandlerFunc = async (c: Context) => { try { const { id } = c.params as { id: string }; if (c.request.headers.get("content-type") !== "application/json") { throw new ErrorHandler("Invalid body", 422); } const body = await (c.body()) as { name?: string; salary: string; age?: string; }; if (!Object.keys(body).length) { throw new ErrorHandler("Request body can not be empty!", 400); } const fetchedEmployee = await employees.findOne({ _id: { "$oid": id } }); if (fetchedEmployee) { const { matchedCount } = await employees.updateOne( { _id: { "$oid": id } }, { $set: body }, ); if (matchedCount) { return c.string("Employee updated successfully!", 204); } return c.string("Unable to update employee"); } throw new ErrorHandler("Employee not found", 404); } catch (error) { throw new ErrorHandler(error.message, error.status || 500); } }; 复制代码
更新成功后回返回对象包含三个字段:
matchedCount
modifiedCount
upsertedId
请求:
返回:
最后,删除员工:
/** * 删除 * @param c Context * @returns msg string */ export const deleteEmployee: HandlerFunc = async (c: Context) => { try { const { id } = c.params as { id: string }; const fetchedEmployee = await employees.findOne({ _id: { "$oid": id } }); if (fetchedEmployee) { const deleteCount = await employees.deleteOne({ _id: { "$oid": id } }); if (deleteCount) { return c.string("Employee deleted successfully!", 204); } throw new ErrorHandler("Unable to delete employee", 400); } throw new ErrorHandler("Employee not found", 404); } catch (error) { throw new ErrorHandler(error.message, error.status || 500); } }; 复制代码
请求:
返回:
代码部分完成了,如今启动服务吧~
deno run --allow-write --allow-read --allow-plugin --allow-net --allow-env --unstable ./server.ts 复制代码
为了确保程序安全执行,deno
默认阻止任何访问磁盘、网络或环境变量的操做。所以,若是想要服务成功运行,你须要加上这些标记:
可能这个时候你会问了:我咋记得住我要加哪些标记?不用担忧,若是缺了哪一个的话,控制台会告诉你的。
成功运行,撒花~
Compile file:///Users/xxxxxx/deno-demo/server.ts
INFO load deno plugin "deno_mongo" from local "/Users/xxxxxx/deno-demo/.deno_plugins/deno_mongo_8834xxxxxxxxxxxxxx8a4c.dylib" server listening on http://localhost:5000 复制代码
译注:能够经过
Postman
等其余工具验证一下接口
在这篇文章里,咱们实现了:
deno
构建 CRUD API 来管理员工信息
deno_mongo
操做
mongodb
数据库
deno
框架
abc
构建服务器
denv
声明环境变量
你可能注意到了 deno
:
package.json
文件或者在
node_modules
目录下安装模块
以上,
译注:XX 学完这个后,这几天又玩了下
Go
语言,发现deno
好多地方和Go
很类似,好比:
Go
也经过 url 引入模块(使用版本1.14.4
)deno
使用原生TypesSript
而Go
自己就是强类型,必须声明类型;而Go
里声明Struct
感受相似 TS 里的interface
可能还有其余的一时想不起来了😝
代码截取自Deno 钻研之术:(1) Hello,从多样化安装到简单实战,有修改。
友情提示:目前 Mac 用户使用 homebrew 安装版本只有 0.4.2
,运行本文章代码会报错。
推荐:Mac 系统使用 curl
方式安装高版本 deno
# 经过 curl 下载远程的安装脚本 install.sh 中的 deno.zip 压缩包到本地并当即执行
$ curl -fsSL https://deno.land/x/install/install.sh | sh # Archive: /Users/${USER_NAME}/.deno/bin/deno.zip # inflating: deno # Deno was installed successfully to /Users/${USER_NAME}/.deno/bin/deno # Manually add the directory to your $HOME/.bash_profile (or similar) # export DENO_INSTALL="/Users/${USER_NAME}/.deno" # export PATH="$DENO_INSTALL/bin:$PATH" # Run '/Users/${USER_NAME}/.deno/bin/deno --help' to get started # 输入 deno -V 并不能运行成功 deno 命令,须要咱们手动配置环境变量来让终端知道 deno 命令该在哪执行。 $ deno -V # zsh: command not found: deno # 注意:${USER_NAME} 是你在本身操做系统下的用户名,须要手动改成本身的用户名。 $ export DENO_INSTALL="/Users/xuxun/.deno" $ export PATH="$DENO_INSTALL/bin:$PATH" $ deno -V deno 1.1.1 $ which deno /Users/xuxun/.deno/bin/deno 复制代码
友情提示:curl 下载 deno 过程可能有点慢,能够选择扔在一边先不去管它。
注:本文部分翻译自 dev.to/slimhmidi/c…,为了便于安装文章调试项目,因此在原文基础上有所删减,另外代码部分因 Deno 及相关插件版本缘由有所改动~
由于第一次正式接触
deno
和Go
,因此若是有不足之处欢迎指出~本文排版用了 Markdown Nice,很好用
对了,以后若是文章内容有更新,会在我博客上进行更新~
Create a server with deno and mongo: https://dev.to/slimhmidi/create-a-server-with-deno-and-mongo-206l
[2]Deno 安装文档: https://github.com/denoland/deno_install
[3]Deno 钻研之术:(1) Hello,从多样化安装到简单实战: https://juejin.im/post/5ebb8b9c5188250bdf5c2d89