Create an Angular Rest API Mock with Deno
Tags: angular, javascript, deno, webdev
Published: 2020-06-09 07:52:51

In one of our Angular courses we are currently using a Node Express server to provide mock data to an Angular application.

As Deno has been released with the official version 1.0 (mid May 2020), I decided to experiment it and write a new web server for the course. The final layout looks like the screenshot below (as you can see nothing fancy from the layout perspective):

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7lxybbz4tj6o0ax1w9ox.png)

This article is a step-by-step, practical guide focused on creating a Rest API, with full CRUD actions, for an Angular application. I will not cover too many details about Deno though, as it would make the post way too long, and there are already plenty of good introductions to Deno already. <br> Below are the topics that we will cover, feel free to follow along or jump directly to the topic of interest if you prefer:

**Deno:**
- [What is Deno](#what_is)
- [Install Deno](#install)
- [Create a server](#server)
- [Start the server](#run)
- [Debugging](#debug)

**Angular:**
- [Create an Angular service](#create_service)

**Repo**
- [Github Repo](#repo)

&nbsp;

# What is Deno <a name="what_is"></a>
[Deno](https://deno.land) has been created by Ryan Dahl, the same creator of Node.js.

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

If you are already familiar with Node, then Deno is able to do exactly the same things, but faster.
 
Deno can be seen as a way to *rewamp* Node.js, solving  different aspects that the same Ryan considered his "regrets". <br> Below is his talk at the JSConf EU 2018, where he exposes these points:

{% youtube M3BM9TB-8yA %}

# Install Deno <a name="install"></a>

We can choose to use a package manager or execute directly a command in the shell.

### Install via command

**With Shell (Mac):**

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

**With PowerShell (Windows):**

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

&nbsp;


### Install via Package Manager

**With [Homebrew](https://formulae.brew.sh/formula/deno) (Mac):**

```sh
brew install deno
```

**With [Chocolatey](https://chocolatey.org/packages/deno) (Windows):**

```powershell
choco install deno
```


&nbsp;

After Deno is downloaded and setup locally, run `deno --version` in the shell to verify the installation. We should get a similar output:

```shell
$ deno --version
deno 1.0.3
v8 8.4.300
typescript 3.9.2
```

&nbsp;
If we want an overview about the available commands, we can invoke the instruction `deno --help`, showing all the available sub-commands. <br> We can even get further details for each single command simply appending the `--help` flag, like: `deno run --help`

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/2gp4uh5si8elx5hltxia.PNG)

&nbsp;

#### Available modules
Deno provides a list of **standard modules**, reviewed by the core team and guaranteed to work with the specific Deno version. These standard modules are hosted at [https://deno.land/std](https://deno.land/std) and provide functionalities for most of the basic tasks like: uuid generation, http calls and file system access, for instance.

Aside these, deno.land website also provides a public hosting service for **third party modules** that are compatible with Deno at [deno.land/x](deno.land/x). <br>We can search among an exhaustive collection of modules.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/w1r66nqkkzfweys440ht.png)

&nbsp;

# Create a Server
Now that everything is in place, let's start writing some code. Define a root folder for your server:

```shell
mkdir webServer && cd webServer 
```
&nbsp;

### Server.ts <a name="server"></a>
Create a `server.ts` file.

> 💡 **Note:** we can use plain JavaScript instead of typescript, but we would lose many of the benefits that typescript offers. Moreover, being Deno written on top of Rust and Typescript, it compiles directly .ts files for us.

#### Use the standard http module
To create an HTTP server we could import the `server.ts` file from the `http` standard module:

```typescript
import { serve } from "https://deno.land/std@0.125.0/http/server.ts";

const server_port = 5400;

function req_handler(req: Request): Response {
  console.log("\nReceived a request...\n");
  const body = JSON.stringify({ message: "I am a DENO server 🦕" });
  return new Response(body, {
    status: 200,
    headers: {
      "content-type": "application/json; charset=utf-8",
    },
  });
}

serve(req_handler, { port: server_port})
console.log("Listening on PORT: ", server_port);
```
&nbsp;
> 💡 **Note:** you might have noticed that we import from a url here rather than from a local path. <br>This is a new concept in Deno, we don't need to have the  packages already installed locally. We can import their latest version and cache it, making it available even while offline. Deno uses ES Modules to import packages, where from Node uses npm. This translates in the absence of the `node_modules` folder and  `package.json` file (we don't have any trace of them in our webServer folder). With Deno we directly import the packages we want through its url.

#### Use third party module
Alternatively we can opt for [`oak`](https://deno.land/x/oak), a middleware framework for Deno's http server, including a router middleware. This middleware framework is inspired by Koa, therefore already familiar to many Node.js developers. For our mock server I decided to use oak.

```typescript
import { Application } from "https://deno.land/x/oak/mod.ts";
import { oakCors } from "https://deno.land/x/cors/mod.ts";
import router from "./src/routes.ts";

const port = 8280;
const app = new Application();

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

app.addEventListener("listen", ({ hostname, port, secure }) => {
    console.log(`--- Listening on: ${secure ? "https://" : "http://"}${
        hostname ?? "localhost"
        }:${port}`
    );
});
await app.listen({ port });
```

&nbsp;
If you already used Express the code above should be already very familiar. After creating an instance of the `Application` class, we can stack multiple middleware using the `use()` method and then activate the server (`listen()` method), waiting for incoming requests.

#### CORS
We can define CORS for our application otherwise we would get a client-side error every time we try to reach our server from the Angular app. Deno provides a cors module (`https://deno.land/x/cors/mod.ts`) with default settings that already capture many common cases. We can enable CORS with the following call: 

```typescript
app.use(oakCors());
```

The default configuration, hence without parameters like in the snippet above, translates in the following set of options:

```json
{
  "origin": "*",
  "methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
  "preflightContinue": false,
  "optionsSuccessStatus": 204
}
```

&nbsp;

### Routes.ts
As our mock server is pretty simple, I decided to create just a folder `src` to host all the business logic and keep it separated from the `server.ts` file.

The routes file contains all the endpoints that we want to expose to the Angular client and in our case implement the classic CRUD operations. 

```typescript
import { Router } from "https://deno.land/x/oak/mod.ts";
import {
    getAllEmployees, getEmployeeById, updateEmployee, addEmployee, deleteEmployee
} from "./employeeApis.ts";

const router = new Router();

router.get("/employees", getAllEmployees)
    .get("/employees/:id", getEmployeeById)
    .put("/employees/:id", updateEmployee)
    .post("/employees", addEmployee)
    .delete("/employees/:id", deleteEmployee);

export default router;
```

&nbsp;

### Employee.ts
We need to define a generic model for our domain. Here we design an `Employee` object with some static data and no database storage, as it would be beyond the course scope, focusing on Angular and client side development only.

```typescript
export interface Employee {
    id: number;
    firstname: string;
    lastname: string;
    email?: string;
}

export const EmployeeData: Employee[] = [
    { id: 1, firstname: 'Larry', lastname: 'Potter', email: 'larry.potter@hotmail.com' },
    { id: 2, firstname: 'Mara', lastname: 'Croft', email: 'mara.croft@gmail.com' },
    { id: 3, firstname: 'Thomas', lastname: 'Müller', email: 'thomas123@gmail.com' },
    { id: 5, firstname: 'Karl', lastname: 'Fritz', email: 'Karl_great@microsoft.com' },
    { id: 6, firstname: 'Paolo', lastname: 'Rossi' }
];
```

&nbsp;

### EmployeeApis.ts
In this file we implement the real logic behind each endpoint. Any data mutation will affect the local data structure *EmployeeData*, seen above. <br> The code is very simple and self-explanatory therefore I won't go in detail about it.

```typescript
import { EmployeeData, Employee } from './employee.ts';

// Returns all available employees
export const getAllEmployees = ({ response }: { response: any }) => {
    response.body = EmployeeData;
};

// Returns one employee by its Id or 404 if not found
export const getEmployeeById = ({ params, response }: { params: { id: string }; response: any }) => {
    const selectedEmployee: Employee | undefined = EmployeeData.find((employee) =>
        employee.id === +params.id
    );
    if (selectedEmployee) {
        response.status = 200;
        response.body = selectedEmployee;
    }
    else {
        response.status = 404;
        response.body = [];
    }
};

// Add a new employee to the list
export const addEmployee = async (
    { request, response }: { request: any; response: any },
) => {
    if (!request.hasBody) {
        response.status = 400;
    } else {
        const newEmployee: Employee = await request.body();

        newEmployee.id = getNextEmployeeId();
        EmployeeData.push(newEmployee);
        response.status = 201;
    }
};

//Provides the next number to be used as employee Id
function getNextEmployeeId(): number {
    let maxId = 1;
    EmployeeData.forEach(p => {
        maxId = Math.max(p.id, maxId);
    });
    return maxId + 1;
}

// Removes an employee by its Id or 404 if not found
export const deleteEmployee = (
    { params, response }: { params: { id: string }; response: any },
) => {
    const targetId = +params.id;
    const newEmployeeList = EmployeeData.filter(x => x.id !== targetId);
    if (newEmployeeList.length < EmployeeData.length) {
        replaceCollection(EmployeeData, newEmployeeList);
        response.status = 200;
    } else {
        response.status = 404;
    }
};

// Updates en existing employee
export const updateEmployee = async (
    { params, request, response }: {
        params: { id: string };
        request: any;
        response: any;
    },
) => {
    const targetId = +params.id;
    let employeeToUpdate: Employee | undefined = EmployeeData.find((employee) =>
        employee.id === targetId
    );
    if (employeeToUpdate) {
        const body = await request.body();
        const newEmployeeData: Employee = body.value;

        let updatedData = EmployeeData.map((e: Employee) => {
            return e.id === targetId ? { ...e, ...newEmployeeData } : e;
        });

        replaceCollection(EmployeeData, updatedData);
        response.status = 200;
    } else {
        response.status = 404;
    }
};

// Replaces the employee data structure with a new collection
function replaceCollection(originalData: Employee[], newData: Employee[]) {
    originalData.splice(0, originalData.length);
    originalData.push(...newData);
}
```

&nbsp;

## Start the server <a name="run"></a>
Now that we created all the needed files, it is time to start the server. Execute the following command in the shell from the path hosting your server file:

```shell
deno  run --allow-net server.ts
```

> ⚠️ **Note:** if you didn't add the Deno install root ($HOME/.deno/bin) to your environment variables, then you have to prepend the file path to server.ts

&nbsp;
By running the command, different modules are downloaded, but no folder inside our solution is created for them. 

```shell
Compile file:///.../server.ts
Download https://deno.land/x/oak/mod.ts
Download https://deno.land/x/oak/application.ts
Download https://deno.land/x/oak/context.ts
Download https://deno.land/x/oak/cookies.ts
Download https://deno.land/x/oak/httpError.ts
Download https://deno.land/x/oak/middleware.ts
Download https://deno.land/x/oak/request.ts
Download https://deno.land/x/oak/response.ts
Download https://deno.land/x/oak/router.ts
Download https://deno.land/x/oak/send.ts
Download https://deno.land/x/oak/types.ts
Download https://deno.land/x/oak/deps.ts
Download https://deno.land/x/oak/keyStack.ts
Download https://deno.land/x/oak/tssCompare.ts
Download https://deno.land/std@v1.0.0-rc1/http/server.ts
...
```

These modules are cached from now on and we do not need to download them again, unless we explicitly want to, using the `--reload` option, for instance. By default, the cached modules are stored in Deno's base directory: $HOME/.deno (DENO_DIR), but we can change this location if we need, typically in the case of a production environment.

`DENO_DIR` contains the following files and directories:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/r6qlhbazqxdu4bdc6xwq.png)

&nbsp;

> 💡 **Note:** in Deno, you need to give explicit permissions before running a program. In the command above we had to grant network access with the option: `--allow-net`

If we omit this option, we get the following error after downloading all the modules:

```shell
error: Uncaught PermissionDenied: network access to "127.0.0.1:8280", run again with the --allow-net flag
    at unwrapResponse ($deno$/ops/dispatch_json.ts:43:11)
    at Object.sendSync ($deno$/ops/dispatch_json.ts:72:10)
    at Object.listen ($deno$/ops/net.ts:51:10)
    at listen ($deno$/net.ts:164:18)
    at Application.serve (server.ts:261:20)
    at Application.listen (application.ts:106:31)
    at server.ts:18:11
```

And that was all we need to create a simple http server to use as a mock for our client application. Let's create now an Angular project that uses our REST APIs.

## Debugging <a name="debug"></a>
Deno supports V8 Inspector Protocol. We can debug Deno programs with Chrome DevTools or other clients that support the protocol.

As most probably we are using Visual Code to implement our Angular application, let's see how we can debug the Deno server directly from our IDE. An official plugin is currently under construction, but for the time being we can create a `launch.json` file:

```JSON
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Deno",
      "type": "node",
      "request": "launch",
      "cwd": "${workspaceFolder}",
      "runtimeExecutable": "deno",
      "runtimeArgs": ["run", "--inspect-brk", "-A", "server.ts"],
      "port": 9229
    }
  ]
}
```
> 💡 **Note:** if you named your script file differently than `server.ts` you have to adapt the last item of "runtimeArgs"  accordingly.

With the configuration above, VS Code debugger will run at: `127.0.0.1:9229` and intercept all the breakpoints we set.

### More about Deno
If you are interested in knowing more about Deno, I recommend the official [blog post](https://deno.land/v1) about the v 1.0 release.

Keep also an eye on the [Deno Cheat Sheet](https://droces.github.io/Deno-Cheat-Sheet/) as it is a great resource to have always an overview about all available commands.

---

&nbsp;

## Create an Angular service<a name="create_service"></a>
For the Angular part, I will describe only the http service calling our REST server. All the code is available on the [Github repo](https://github.com/pacoita/deno-api-mock) anyway and you can download the whole project.

If you don't have already an existing Angular application and you need instructions on how to create one, have a look at my post [about it](https://dev.to/paco_ita/create-progressive-web-apps-with-angular-workbox-pwa-builder-step-4-27d#angular).

### EmployeeService.ts
Thanks to schematics, generate files in Angular is very easy:

```shell
ng g service employee
```
&nbsp;
This command creates the `EmployeeService.ts` and its unit test file. In the service, we define the methods implementing the CRUD operations and that will call the endpoints of the Deno server that we implemented before. 


```typescript
import { Employee } from './../model/employee.model';
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { Observable ,  of ,  throwError as _throw } from 'rxjs';
import { catchError, delay, map } from 'rxjs/operators';
import { environment } from '../../../environments/environment';

@Injectable()
export class EmployeeService {

    constructor(private http: HttpClient) { }

    getEmployees(): Observable<Employee[]> {
        return this.http
          .get<Employee[]>(`${environment.apiBaseUrl}/employees`)
          .pipe(catchError((error: any) => _throw(error)));
      }


    getEmployee(id: number): Observable<Employee> {
      return this.http
        .get<Employee>(`${environment.apiBaseUrl}/employees/${id}`)
        .pipe(catchError((error: any) => _throw(error)));
    }

      createEmployee(payload: Employee): Observable<Employee> {
        return this.http
          .post<Employee>(`${environment.apiBaseUrl}/employees`, payload)
          .pipe(catchError((error: any) => _throw(error)));
      }

      updateEmployee(payload: Employee): Observable<Employee> {
        return this.http
          .put<Employee>(`${environment.apiBaseUrl}/employees/${payload.id}`, payload)
          .pipe(catchError((error: any) => _throw(error)));
      }

      removeEmployee(payload: Employee): Observable<any> {
        return this.http
          .delete<any>(`${environment.apiBaseUrl}/employees/${payload.id}`)
          .pipe(catchError((error: any) => _throw(error)));
      }

}

```

&nbsp;
### Environment.ts

In the file `environment.ts` we can save the base url for the server and eventually other configuration keys. `environment.prod.ts`, reserved for prod builds, typically has keys with different values, to target the production server instead of the staging one.

```typescript
export const environment = {
  production: false,
  apiBaseUrl: 'http://localhost:8280'
};
```

&nbsp;

## Conclusion 
As we saw, it is very easy to create a web server with Deno and use it as a mock for our client application.

This architecture is very convenient because it allows to decouple our web app from the server mocks. We can execute real network calls from our client without need to apply any change to our Angular app before deploying it to production.

&nbsp;

## Github Repo <a name="repo"></a>
The sample code (Angular and Deno server) is available on Github: https://github.com/pacoita/deno-api-mock