⚡A powerful HTTP router and URL matcher for building Deno web servers with dragon 🐲.

Tags: deno, programming, tutorial
Published: 2021-01-14 20:42:59

Dragon is a simple, fast and low HTTP router and URL matcher for building Deno servers. If you need performance and good productivity, you will love it.

Dragon is exchangeable with other web application frameworks for the backend the same way as React.js is exchangeable with Vue.js and Angular.js when it comes to frontend applications.

That being said, let’s now move further with this article and find out the various features of this framework. Below I have picked out a few of the most important features of Dragon:

- Lightweight and modular design allows for a flexible framework. 
- Focus on high performance.
- Middleware support, incoming HTTP request can be handled by a chain of middlewares and the final action.
- It helps in simplifying the configuration and customization steps for the application.

These were a few of the major advantages of using Dragon in web application development. Let's start by using Dragon in your Deno application. 

First things first let's install Deno. I am on a Ubuntu OS  so I am using Shell. Simply open your terminal and type:

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

Next step is specifying Deno’s path to bash.

```sh
nano ~/.bashrc
export DENO_INSTALL="/home/$USER/.deno"
export PATH="$DENO_INSTALL/bin:$PATH"
```

Once you have it installed, close the terminal, open a new one, and type:

```sh
deno --version
```

It should output something like this:

```sh
deno 1.6.3 (release, x86_64-unknown-linux-gnu)
v8 8.8.294
typescript 4.1.3
```

> 💬 If you are using a different operating system, just head over to [deno.land installation](https://deno.land/#installation). They have a lot of ways you can easily install it on your machine.

Awesome! 

Let's move ahead

- Create a new folder and call it **dragon_demo** (but you can call it anything you want)

- Once you create a folder simply `cd` into your new project. Create a file called `server.ts`.

In your `src/server.ts` TypeScript file, use the following code to import Dragon, to create an instance of an Dragon application:

```ts
import { Application, RequestMethod, HttpRequest, HttpResponse } from "https://deno.land/x/dragon@v1.1.0/lib/mod.ts";
const app = new Application();

app.listenAndServe({ port: 8080 });

console.log("🐉 Serveur listining");
```
Let's run this file. Open your terminal and in your project root folder type:

```sh
$ deno run --allow-net server.ts
```

> 💬 Deno is secure by default. Therefore, unless you specifically enable it, a deno module has no file, network, or environment access for example.

You should get something like this:

```sh
🐉 Serveur listining
```

When you run deno run `---allow-net <file_name>` in your terminal, Deno will look at all your imports and install them locally in your machine if they are not there.

The first time you run this it will go to this URL `https://deno.land/x/dragon@v1.1.0/lib/mod.ts` and install the dragon package.

In the next line we do this:

```ts
const app = new Application();
```

This creates a new instance of our application with various options, and it will be the basis of everything as you progress further in this tutorial.

An instance of application has some optional properties as well:

- `hostname`: A unique name for a computer or network node in a network. This defaults to `0.0.0.0`.

- `port`: Numbers used by protocols for operation of network applications.

- `certFile`: A concatenation of all Certificate Authority (CA).

> 🖇 Learn more about [application options](https://github.com/xanny-projects/dragon#installation)

Then we write:

```ts
app.listenAndServe({ port: 8080 });
```

Here the port number and tell Deno to listen to the port, which is 8080. 

Let's register two routes mapping URL path to handler.

> 💬 We believe development must be an enjoyable and creative experience to be truly fulfilling (`HttpRequest`, `HttpResponse`) as parameters.

```ts
const r = app.routes();
  r.Path("/hello")
  .withMethods(RequestMethod.GET)
  .handleFunc(async function (Request: HttpRequest, ResponseWriter: HttpResponse) {
    ResponseWriter.withBody("Hello Dragon").end();
  });
```

We create a new router instance by doing `const r = app.routes();` and then we create a new route called `hello` which is of type `RequestMethod.GET`. If an incoming request URL matches one of the paths, the corresponding handler is called passing. 

> 💬 By default Dragon all methods for this route(s) like `PUT`, `DELETE`, `PATCH`

And now we are done. ✅ Let's run this and see what we have:

```sh
$ deno run --allow-net server.ts
```

Now open your favorite browser and go to `http://localhost:8080/hello`. You will see something like this:

```sh
Hello Dragon
```

Awesome

Honestly the hardest part is done. Conceptually we are 50% there.

Now we only have two things remaining:

- Add a not found route so that when the user tries to access an unknown route.
- Add a logger middleware that consoles the response time.

Using the `notFoundHandler` options you may define a route that will be executed when no other route matches the incoming request.

```ts
const fallback = async function(Request: HttpRequest, ResponseWriter: HttpResponse) {
  ResponseWriter.html`🤦 Page Not Found`.end();
  return MiddlewareState.Cancel;
}

const r = app.routes({
  notFoundHandler: fallback
});
```

fallback is a `Middleware` literally means anything you put in the middle of one layer of the software and another. As you can see fallback has access to the `HttpRequest` and `HttpResponse`. Middleware can either terminate the HTTP request or pass it on to another middleware function using `MiddlewareState.Next` or `MiddlewareState.Cancel`

Let's see if this works.

Restart the server:

```sh
$ deno run --allow-net server.ts
```

Open up a new tab Set the request to `GET` and in the `URL` bar type `http://localhost:8080/something-unknown`.
You should get something like this:

```sh
🤦 Page Not Found
```

Logging Response time in console, create a new file called `logger.ts` and enter the following code:

```ts
import { HttpRequest, HttpResponse, MiddlewareState } from "https://deno.land/x/dragon@v1.1.0/lib/mod.ts";

export const Logger = async function(Request: HttpRequest, ResponseWriter: HttpResponse) {
  //
  console.log(`Handle at: ${Date.now()}`);
  return MiddlewareState.Next;
}
```

In your `server.ts` file add this code:

Now let's import and register the middleware.

```ts
import { Application, RequestMethod, HttpRequest, HttpResponse } from "https://deno.land/x/dragon@v1.1.0/lib/mod.ts";
import { Logger } from "./logger.ts"; 

const app = new Application();

const r = app.routes({ maxRoutes:2 });

r.Path("/hello")
 .withMethods(RequestMethod.GET)
 .handleFunc(async function (Request: HttpRequest, ResponseWriter: HttpResponse) {
      ResponseWriter.withBody("Hello Dragon").end();
  }).middleware(Logger);

app.listenAndServe({ port: 8080 });

console.log("🐉 Serveur listining");

```

I hope that you found this article useful and that it was able to help you learn something today.

If you are interested in joining the dragon team to improve the framework, You are welcome.

A Star 🌟 on our [github repository](https://github.com/xanny-projects/dragon) could be a good and very feedback for us.