如何写出你的第一个Deno服务器

204 阅读4分钟

今天我们要用60行写出我们的第一个Deno服务器。Deno自称是一个 "简单、现代、安全的JavaScript和TypeScript的运行时,使用V8并以Rust构建"。我是TypeScript的超级粉丝,所以我很高兴听到一个将TypeScript视为一等公民的运行时!"。

开始使用

首先,我们必须安装运行时。

一旦Deno安装完毕,你应该能够在你的命令行中输入deno --version ,并看到类似这样的东西。

deno 1.0.0
v8 8.4.300
typescript 3.9.2

Deno还很年轻,而且发展很快,所以如果你有一个更新的版本,我也不会感到惊讶!

指定我们的域

对于我们的第一个服务器,让我们假装我们正在维护某种虚拟书架。因此,我们的领域是关于书籍的。我们可以使用typescript来指定我们的Book 类型,并创建一个带有初始项目的books 数组。让我们在一个新的目录中创建这个文件,并将该文件称为server.ts

server.ts

type Book = {
  id: number;
  title: string;
  author: string;
};

const books: Book[] = [
  {
    id: 1,
    title: 'The Hobbit',
    author: 'J. R. R. Tolkien',
  },
];

抓取一个服务器库

到目前为止,橡木服务器库似乎是Deno最普遍的服务器库。让我们使用它吧!

如果你熟悉node,你可能会认为我们使用一个安装命令,并在某种类似package.jon的文件中维护我们的版本。不是这样的!相反,我们在导入语句中指定包的网址,并在导入时确定版本。Deno将首先查看我们是否有一个资源的缓存版本,如果没有,将获取并缓存它。

重要的是,注意我们指定的是Oak的4.0.0版本。如果我们不指定版本,我们就会得到最新的版本!考虑到沿途可能出现的破坏性变化,这似乎很危险。

我们将从Oak导入ApplicationRouter 。它们将分别创建我们的应用服务器和允许我们配置路由。

我们可以给我们的根网址添加一个get 路由,以响应 "Hello world!"我们告诉我们的应用程序听从8000端口。

import { Application, Router } from 'https://deno.land/x/oak@v4.0.0/mod.ts';

const app = new Application();
const router = new Router();

router.get('/', (context) => {
  context.response.body = 'Hello world!';
});

app.use(router.routes());

await app.listen({ port: 8000 });

这是一个正在运行的服务器,所以我们应该测试一下它在有你的文件的目录中,运行以下命令。

deno run --allow-net server.ts

你的应用程序现在正在监听8000端口,所以你应该能够在你的浏览器中导航到http://localhost:8000 ,并看到我们的Hello World的例子!

添加我们的路由

我们现在可以添加一些路由了!我将在我们的图书资源上设置一些常见的CRUD路由:get book ,查看所有的图书;get book:id ,查看特定的图书;post book ,创建一本书。

import { Application, Router } from 'https://deno.land/x/oak@v4.0.0/mod.ts';

type Book = {
  id: number;
  title: string;
  author: string;
};

const books: Book[] = [
  {
    id: 1,
    title: 'The Hobbit',
    author: 'J. R. R. Tolkien',
  },
];

const app = new Application();

const router = new Router();

router
  .get('/', (context) => {
    context.response.body = 'Hello world!';
  })
  .get('/book', (context) => {
    context.response.body = books;
  })
  .get('/book/:id', (context) => {
    if (context.params && context.params.id) {
      const id = context.params.id;
      context.response.body = books.find((book) => book.id === parseInt(id));
    }
  })
  .post('/book', async (context) => {
    const body = await context.request.body();
    if (!body.value.title || !body.value.author) {
      context.response.status = 400;
      return;
    }
    const newBook: Book = {
      id: 2,
      title: body.value.title,
      author: body.value.author,
    };
    books.push(newBook);
    context.response.status = 201;
  });

app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 8000 });

我认为这段代码中唯一可能是新的或未解释的部分是app.use(router.allowedMethods()); 。这只是一个方便的中间件,它可以让客户知道某个路由方法是不允许的!

最后的触摸。日志中间件

让我们来添加最后一项内容:记录中间件,记录每个请求所需的时间。

import { Application, Router } from 'https://deno.land/x/oak@v4.0.0/mod.ts';

type Book = {
  id: number;
  title: string;
  author: string;
};

const books: Book[] = [
  {
    id: 1,
    title: 'The Hobbit',
    author: 'J. R. R. Tolkien',
  },
];

const app = new Application();

// Logger
app.use(async (ctx, next) => {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  console.log(`${ctx.request.method} ${ctx.request.url} - ${ms}ms`);
});

const router = new Router();

router
  .get('/', (context) => {
    context.response.body = 'Hello world!';
  })
  .get('/book', (context) => {
    context.response.body = books;
  })
  .get('/book/:id', (context) => {
    if (context.params && context.params.id) {
      let id = context.params.id;
      context.response.body = books.find((book) => book.id === parseInt(id));
    }
  })
  .post('/book', async (context) => {
    const body = await context.request.body();
    if (!body.value.title || !body.value.author) {
      context.response.status = 400;
      return;
    }
    const newBook: Book = {
      id: 2,
      title: body.value.title,
      author: body.value.author,
    };
    books.push(newBook);
    context.response.status = 201;
  });

app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 8000 });

现在,无论你什么时候碰到我们的服务器,路由路径和发送响应所需的时间都会被记录到控制台。

就这样,你拥有了它!我们的第一个Deno服务器只有60行。我是Deno的超级粉丝,期待着随着它的发展了解更多的信息。我确实有一些问题和担忧(例如,鉴于缺乏锁文件,我想知道Deno是否以及如何让开发者控制间接依赖),但现在我只是在享受修补这个新玩具的乐趣。