One Hour with Deno
Tags: deno, typescript, beginners, programming
Published: 2022-05-07 15:35:07

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](https://deno.land/)

 
It was created by [Ryan Dahl](https://en.wikipedia.org/wiki/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:
```bash
❯ brew install deno
❯ echo "console.log('Hello, Deno!')" >  hello.ts
❯ deno run hello.ts
Check file:///Users/shikloshi/projects/deno/hello.ts
Hello, Deno!
```

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](https://en.wikipedia.org/wiki/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.

> :warning: 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`](https://deno.land/x/destjs@v0.2.0) soon so let's import it to our `main.ts` file and create our app:

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

createApp({port: 8000});
```


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`.

> :warning: 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](https://en.wikipedia.org/wiki/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:

```typescript
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 }
  }
}
```

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:

```bash
❯ 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)
```

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.

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

2 directories, 2 files
```

After creating this directory structure our command can execute succesfully:

```bash
❯ 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
```



### 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:

```bash
❯ curl localhost:8000/plants
{"plant":"Monstera","beautiful":true}
```



### 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](https://deno.land/manual/getting_started/permissions) 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](https://oakserver.github.io/oak/) -  middleware framework for Deno's native HTTP server. 'destjs' use it under the hood.
* [NestJS](https://docs.nestjs.com/) - 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](https://www.youtube.com/watch?v=M3BM9TB-8yA&t=1s) `Deno` - Recommended!


Stay tuned.