Jefferson DanielNavigate back to the homepage

getting started with Deno

Jefferson Daniel
May 31st, 2020 · 4 min read

Index

  1. Introduction
  2. How install
  3. Hello world
  4. Dependencies
  5. Simple API demo
  6. More about Deno

Introduction

Maybe the better way to introduce the Deno is explaining who is your creator and the javascript runtime environment created by him years ago, Ryan Dahl create the Node in 2009 was the first server-side javascript environment, that is before Node, javascript was just executed in browsers. The node made much success but in 2018 in the same conference where Ryan introduce the Node he presented 10 Things I Regret About Node.js where he pointed his regressions and introduce your new project the Deno.

“Deno is a simple, modern and secure runtime for JavaScript and TypeScript that uses V8 and is built in Rust.”

How Install

You can install the Deno in Windows, MacOS and Linux without very difficult, but the installation will depends of the operational system you use, soo, you can skip directly to installation in your SO, how I use macOS the rest of examples in this post will be executed in this SO.

Linux

In this operational system the one way to install then in official documentation is:

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

If you use MacOS, you can install with the same command above too, but if you use the package manager Brew, you can install with the command:

1brew install deno
Windows

Case you don’t use any package manager, you can install in Power Shell with command bellow:

1iwr https://deno.land/x/install/install.ps1 -useb | iex

Now in the case of package manager the installation is very similar, with chocolatey:

1choco install deno

And finally with scoop

1scoop install deno

After the installation to check if always is ok, you can verify the version of Deno, you should get a message like this:

1$ deno --version
2deno 1.0.1
3v8 8.4.300
4typescript 3.9.2

Hello world

We can get started with a simple server, this block of code bellow are in main page of Deno, in this few lines if youve contact with node, you to perceive some differences. But let’s run this code to see what happens.

deno run welcome.ts

1// welcome.ts
2import { serve } from "https://deno.land/std@0.50.0/http/server.ts";
3const s = serve({ port: 8000 });
4console.log("http://localhost:8000/");
5for await (const req of s) {
6 req.respond({ body: "Hello World\n" });
7}

Running this you will get an error:

1error: Uncaught PermissionDenied: network access to "0.0.0.0:8000",
2run again with the --allow-net flag
3 at unwrapResponse ($deno$/ops/dispatch_json.ts:43:11)
4 at Object.sendSync ($deno$/ops/dispatch_json.ts:72:10)
5 at Object.listen ($deno$/ops/net.ts:51:10)
6 at listen ($deno$/net.ts:152:22)
7 at serve (https://deno.land/std@0.50.0/http/server.ts:261:20)
8 at file:///Users/jefferson.silva/Projects/test-deno/index.ts:2:11

This revel a very important part of Deno, be secure by default, anything is disabled unless you change it, it serve to File system, network or environment access, soo to run this demo server you need some command like this:

deno run --allow-net welcome.ts.

Write every time this flags can be bussing, so to simplify I create a Makefile to some Deno commands. The fmt command will auto-formats TypeScript and JavaScript code.

1# Makefile
2
3serve:
4 deno run --allow-net welcome.ts
5
6fmt:
7 deno fmt

Dependencies

In Deno the third-party imports are called by URLs like javascript script in the browser, the download of this imports are made just at the first time, when you do it, this module was save in $HOME/Library/Caches/deno.

This imports is an exception of the network access, in example above where we don’t pass any flag, the Deno made the download with success and just after when he tries execute de server occurred the error, because the runtime has special access to download imports and cache then to disk.

The local imports is very similar to imports in Node, but in this case is required use the extension of files. I will create an another file just for example, and put in him the port constant.

1// constants.ts
2export const port = 8000

To import this file in our welcome, we need pass the relative path of file along with your extension. With this, I put this variable in server configuration, and in the log about here the server are running.

1import { port } from "./constants.ts"
2
3import { serve } from "https://deno.land/std@0.50.0/http/server.ts";
4const s = serve({ port });
5console.log(`http://localhost:${port}/`);
6for await (const req of s) {
7 req.respond({ body: "Hello World\n" });
8}

Different of Node, the Deno has no node_modules, a folder inside project with all dependencies, or package.json, a file with a list of dependencies that the project use. How I comment above the dependencies is saved globally and the dependencies and your versions stayed just in each file when you import then.

Simple API demo

For explore a little more the Deno let’s go write a simple application using the Oak a middleware framework for Deno, the objetive is just see how we can configure variable environments, routers, controllers, etc… soo we will use a static data in a typescript file. To this example we will need this list of files:

  • Makefile
  • .env
  • server.ts
  • app.ts
  • router.ts
  • controller.ts
  • db.ts

To start let’s create config files, I will create a Makefile to have the Deno commands more easily, are just two descriptive commands, one for format e another to run the server, and I configured the server to format the application every time before run. Note that I already pass to the Deno run the flags that are necessary to the application works well. verify if your Makefile are using tabs and not spaces.

If we use just Deno to run the application, after every change in code we need to stop the server and run it again, over time it start to get tiring, so I use denon this module update the server automatically for us. In the link has instructions to how install.

1# Makefile
2
3serve: fmt
4 denon run --allow-net --allow-read server.ts
5fmt:
6 deno fmt

And an environment file to put the port that our application will use.

1# .env
2
3PORT=9000

In server file that was executed in our Makefile, we need to get the PORT variable that was put in our environment file, to do it was used the dotenv module, he exports a config function that returns all of our variables. And we need the app file too, where are configured the application.

1// server.ts
2
3import { config } from "https://deno.land/x/dotenv/mod.ts";
4import { app } from "./app.ts";
5
6const { PORT } = config();
7
8console.log(`Server listening on ${PORT} 🦕`);
9await app.listen({ port: parseInt(PORT) });

Some configurations in app file is necessary too, we just need start the application using the oak framework and pass some middleware, the routers and the permission of methods.

1// app.ts
2
3import { Application } from "https://deno.land/x/oak/mod.ts";
4
5import { router } from "./router.ts";
6
7export const app = new Application();
8
9app.use(router.routes());
10app.use(router.allowedMethods());

The router file is responsible to declare all routers of the application and say which HTTP methods this routers accept, in this example we will use just the get methods for keep it simple. The first route will return all resources, and the last just what match with the passed id.

1// router.ts
2
3import { Router } from "https://deno.land/x/oak/mod.ts";
4
5import { getBooks, getBook } from "./controller.ts";
6
7export const router = new Router();
8
9router
10 .get("/book", getBooks)
11 .get("/book/:id", getBook);

The routers are configured above but who handle with request is the controller, in here we put what the application will response back to who requisite this route.

1// controller.ts
2
3import { books } from "./db.ts";
4import { RouterContext } from "https://deno.land/x/oak/router.ts";
5
6export const getBooks = async (context: RouterContext) => {
7 context.response.body = Array.from(books.values());
8};
9
10export const getBook = async (context: RouterContext) => {
11 if (context.params && context.params.id && books.has(context.params.id)) {
12 context.response.body = books.get(context.params.id);
13 }
14};

And finally in our db file, we put a Map with some books data.

1// db.ts
2
3interface Book {
4 id: string;
5 title: string;
6 authors: string;
7}
8
9export const books = new Map<string, Book>();
10
11books.set("1", {
12 id: "1",
13 title: "Production-Ready Microservices",
14 authors: "Susan J. Fowler",
15});
16
17books.set("2", {
18 id: "2",
19 title: "Design Patterns: Elements of Reusable Object-Oriented Software",
20 authors: "Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides",
21});

Running the application with our Makefile executing the command make serve, you got it some like that:

1$ make serve
2deno fmt
3denon run --allow-net --allow-read server.ts
4[denon] v2.0.2
5[denon] watching path(s): *.*
6[denon] watching extensions: ts,js,json
7[denon] starting `deno run --allow-net --allow-read server.ts`
8Compile file:///Users/your-user/project-folder/server.ts
9Server listening on 9000 🦕

To test our routes you can execute some cURL commands in your terminal, json_pp is just for return a response more prettier, the response will be something like this:

1$ curl http://localhost:9000/book | json_pp
2
3[
4 {
5 "id" : "1",
6 "title" : "Production-Ready Microservices",
7 "authors" : "Susan J. Fowler"
8 },
9 {
10 "id" : "2",
11 "title" : "Design Patterns: Elements of Reusable Object-Oriented Software",
12 "authors" : "Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides"
13 }
14]
15
16$ curl http://localhost:9000/book/1 | json_pp
17
18{
19 "id" : "1",
20 "title" : "Production-Ready Microservices",
21 "authors" : "Susan J. Fowler"
22}

More about Deno

More articles from Jefferson Daniel

using currying in javascript

Index Introduction History Currying vs partial application Partial Application Currying Who use Real world examples Conclusion Introduction…

December 21st, 2017 · 3 min read

taking more advantage of SASS

Exist some feature in SASS that is not very popular, but they can help us to save time when we are building our applications.

August 21st, 2016 · 3 min read
© 2015–2020 Jefferson Daniel
Link to $https://github.com/jeffersondanielssLink to $https://linkedin.com/in/jeffersondanielss