DEV Community

Aviad Shikloshi
Aviad Shikloshi

Posted on

One Hour with Deno

Part of my Saturday morning routine is to explore a new technology I find interesting. It's limited to one hour so that I won't drift away and stay focused.

Usually it begins with a simple "Hello, World" to setup my environment, and continues on to discover some basics around the eco system.

If it's a new runtime or a programming language, I will try to setup something a bit more realistic than the hello-world example - REST API most of the time will do the trick.

Hello, Deno!

Deno is a simple, modern and secure runtime for JavaScript, TypeScript, and WebAssembly that uses V8 and is built in Rust.
from Official website

It was created by Ryan Dahl who also authored Node.js and while it's not suppose to be a replacement, it does try to fix some of Node.js disadvantages.

Let's start! For mac users all you need to do is:

❯ brew install deno
❯ echo "console.log('Hello, Deno!')" >  hello.ts
❯ deno run hello.ts
Check file:///Users/shikloshi/projects/deno/hello.ts
Hello, Deno!
Enter fullscreen mode Exit fullscreen mode

This is a working Deno application.

What about NPM and node_modules?

Deno was first introduced in order to fix a lot of the things going on with Node.js eco system that Ryan Dahl was not a fan of.

Package management and npm was always kind of controversial topics in Node.js community but either way, we did learned a lot from this approach.

In Deno there is no real package manager for now, and no node_modules directory that holds all your project dependencies.

If you want to use Deno third party libraries you can do it via Remote Imports.

⚠️ This is a very wide and interesting topic that I would probably invest time in understanding deeply in the future.

We will start using destjs soon so let's import it to our main.ts file and create our app:

import { createApp } from "https://deno.land/x/destjs@v0.1.2/mod.ts" // This is a remote import - NEAT

createApp({port: 8000});
Enter fullscreen mode Exit fullscreen mode

For now - createApp - simply initalize our app with our controllers and expose endpoints via oak http server.
When running this, we can access our app via localhost:8000.

⚠️ If you are not familiar with NestJS - I would say that the library expects files to be located in a specific directory tree (a type of convention over configuration). For instance: any exported class from controllers directory, with the compelling decorators, gets registered as a server endpoint.

Let's create our first application controller. Simply put, controller is where our HTTP endpoints are being defined and where we call any business logic related to this endpoint.

We will call our first controller controller/plant.controller.ts and for now it will look like this:

import { Controller, Get } from "https://deno.land/x/destjs@v0.2.0/mod.ts" // 3
import { HttpContext } from "https://deno.land/x/destjs@v0.2.0/types.ts";


@Controller("/plants") // (1)
export default class PlantsController {

  @Get("/") // (2) 
  getOne(context: HttpContext) {
    console.log(context.state)
    return { plant: "Monstera", beautiful: true }
  }
}
Enter fullscreen mode Exit fullscreen mode

When we call this controller endpoint http://localhost:8000/plants with a HTTP GET request, we get in response a beautiful Monstera. Later on we will use a database to store our plants and do some operations on it.

Let's zoom in on a few things:
  • (1) @Controller('/plants') decorator - For now, what we need to know about it is that it create a family of HTTP endpoints that is accessible in our application. Here we can see /plants endpoint.
  • (2) @Get('/') decorator for fetching a plant with HTTP GET request to /plants.
  • (3) Remote Import for our library.

This is a standart NestJS way of minimzing a lot of the boilerplate we used to have with Express.js.

Troubleshoot library issues

This is where it was suppose to run, but an error occurs:

❯ deno run --allow-net --allow-read ./main.ts
error: Uncaught (in promise) NotFound: No such file or directory (os error 2), readdir 'middlewares'
  for await (const item of Deno.readDir(name)) {
                   ^
    at async Object.[Symbol.asyncIterator] (deno:runtime/js/30_fs.js:125:16)
    at async readFolder (https://deno.land/x/destjs@v0.2.0/bootstrap/middlewares.ts:8:20)
    at async initializeMiddlewares (https://deno.land/x/destjs@v0.2.0/bootstrap/middlewares.ts:27:3)
    at async createApp (https://deno.land/x/destjs@v0.2.0/mod.ts:19:3)
Enter fullscreen mode Exit fullscreen mode

Currently destjs will fail if it didn't find middlewares directory under our project root directory. I'm not sure this behavior is by design or a bug - But for now we will create it even if we are not going to write any middlewares.

❯ tree -L 2
.
├── controllers
│   └── plants.controller.ts
├── main.ts
└── middlewares

2 directories, 2 files
Enter fullscreen mode Exit fullscreen mode

After creating this directory structure our command can execute succesfully:

❯ deno run --allow-net --allow-read ./main.ts
 Middlewares initialized! 0ms
Check file:///Users/shikloshi/projects/deno/hello-deno/controllers/plants.controller.ts
 Controllers initialized! 2106ms
 DestJS application ready at port 8000
Enter fullscreen mode Exit fullscreen mode

Test it using curl

Using curl http client we are able to submit an http request and verify that we are indeed getting the http response we are expecting to see:

❯ curl localhost:8000/plants
{"plant":"Monstera","beautiful":true}
Enter fullscreen mode Exit fullscreen mode

Permission flags

Deno, unlike Node.js, does not get allowed permissions by default to use host network and file system.

  • destjs is going to read from disk at build time so deno will beed to get explicit permission to do so by adding --allow-read.
  • When running the server, it will have to use host network features and get explicit permissions using --allow-net. I encourage you to explore permission flags in depth when getting to know Deno.

Whats next?

In the next few chapter of this post We will try to:

  • Add persistence layer using PostgreSQL.
  • Authentication layer using middlewares.
  • We will also explore openAPI.
  • Enhance our API to do some really interesting things, like saving plants in DB and checking when it was last watered.

Further reading

If you liked this piece and want to deepen your understanding of some of the underlying concepts. Here are some links:

  • Oak server - middleware framework for Deno's native HTTP server. 'destjs' use it under the hood.
  • NestJS - amazing framework on top of Express.js that is being "ported", so to speak, into Deno. It has great concepts and helps us write business logic on top of well designed construct.
  • Ryan Dahl first introducing Deno - Recommended!

Stay tuned.

Top comments (0)