The goal of this post is to give a step-by-step guide on how to set up a Proof of Concept (PoC) project using Deno and Angular. The PoC covers the following topics:
- Setting up a Deno server
- Generating an Angular application
- Serve the Angular application with Deno
- Call an endpoint of Deno from the Angular app
The result of this guide can be found on GitHub.
The project can be easily used for playing around with this stack. In the following sections, I show how to set it up.
Setting up the Deno server to serve the Angular app
- First of all, Deno has to be installed based on the installation guide. Please follow the installation instructions and when it is finished check the installation with running
deno run https://deno.land/std/examples/welcome.tsfrom the command line. The result should be similar to this:
- When it is successfully installed, create the project folder. In my case, it is
angular-deno-stack-poc. In this folder a subfolder has to be created for the server, the folder name isserver. - Let's open a Visual Studio Code in
angular-deno-stack-poc\serverfolder and create a TypeScript file calledserver.ts. - To download the
index.htmlof the Angular app following code snippet is needed as first iteration:
import { Application, send } from "https://deno.land/x/oak/mod.ts";
const app = new Application();
app.use(async (context) => {
await send(context, context.request.url.pathname, {
root: `${Deno.cwd()}/../client-app/dist/angular-deno-poc`,
index: "index.html",
});
});
app.listen({ port: 8080 });
console.log(`Listening on localhost:${8080}`);
The above code uses oak middleware.
Details about it can be found in the official documentation.
The above code snippet assumes that a built Angular application exists on ./../client-app/dist/angular-deno-poc path. I describe in the next section how to create it.
Generate the Angular app
- Install Node.js LTS if it is not installed yet on the computer.
- If the Angular CLI is not installed globally yet install it with running
npm install -g @angular/cliin the command line. If we typeng --versionin the command line and the version is printed out then the installation was successful. - In the terminal let's go back to the
angular-deno-stack-pocfolder and runng new angular-deno-poc. The Angular CLI asks some questions, I choose to use routing and use scss.
- Rename the created folder to
client-app. This way the Angular app is namedangular-deno-pocin the development environment and it is located in theclient-appfolder.
- Navigate in terminal in the
client-appfolder and runnpm run build -- --prod. This way a production build is created in thedistfolder. If the build was successful the terminal shows the following output:
The app is ready, let's check if it can be served with the Deno server.
Check the app in the browser
- Navigate in command line in
angular-deno-stack-poc\serverand rundeno run --allow-net --allow-read .\server.tscommand. The server will listen on port 8080.
- Open a browser and navigate to
http://localhost:8080/. If every step was successful, the boilerplate code of Angular CLI is displayed.
Now we have a running Deno server that serves the Angular app. As the next step, an endpoint is created and the Angular app will fetch some data from there.
Add an endpoint to the server and fetch data from Angular
We are going to send a message string and a timestamp from the server to the client.
Create a Data Transfer Object
- First a Data Transfer Object (Dto) is created, which describes the traveling data between the client and the server-side. As we have TypeScript on both sides of the stack, we can use the same TypeScript file for this. Let's create a new folder in
angular-deno-stack-pocroot folder, it should be calledcommon.
- In the common folder the
message-dto.tsfile has to be created with the following content:
export interface MessageDto {
message: string;
timeStamp: string;
}
Create the endpoint
- As the next step the server code has to import the file created above and the endpoint has to be created. It means, that after update the server code has to look like this:
import { Application, send, Router } from "https://deno.land/x/oak/mod.ts";
import { MessageDto } from "./../common/message-dto.ts";
const app = new Application();
const router = new Router();
router
.get("/api/message", (ctx) => {
const message: MessageDto = {message: "Hello from API!", timeStamp: new Date().toTimeString()}
ctx.response.body = message;
});
app.use(router.routes());
app.use(router.allowedMethods());
app.use(async (context) => {
await send(context, context.request.url.pathname, {
root: `${Deno.cwd()}/../client-app/dist/angular-deno-poc`,
index: "index.html",
});
});
app.listen({ port: 8080 });
console.log(`Listening on localhost:${8080}`);
After the code modification resart the Deno server.
The endpoint sends response to get requests on
/api/messageroute. It can be check from the browser with navigating tohttp://localhost:8080/api/messageurl.

Add a service to Angular
To fetch data from the server an Angular service has to be used.
- In
angular-deno-stack-poc\client-app\src\appcreate thecorefolder and create a file calledexample.service.ts. The content of it should be the following:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { MessageDto } from '../../../../common/message-dto'
@Injectable()
export class ExampleService {
constructor(private http: HttpClient) { }
getExampleMessage(): Observable<MessageDto> {
return this.http.get<MessageDto>('/api/message');
}
}
- In
app.module.tsimport theHttpClientModuleand addExampleServiceto the providers. The content of the file should be following:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';
import { ExampleService } from './core/example.service';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule
],
providers: [ExampleService],
bootstrap: [AppComponent]
})
export class AppModule { }
- To display the fetched data change
app.component.tscontent to the below snippet:
import { Component } from '@angular/core';
import { ExampleService } from './core/example.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
message: string;
timeStamp: string;
constructor(private exampleService: ExampleService) { }
ngOnInit() {
this.exampleService.getExampleMessage().subscribe((result) => {
this.message = result.message;
this.timeStamp = result.timeStamp;
});
}
}
And change app.component.html to
<h3>Message from the server API:</h3>
<p>{{message}}</p>
<p>{{timeStamp}}</p>
- After the changes, the Angular app has to be rebuilt. Run
npm run build -- --prodfrom theangular-deno-stack-poc\client-appin command line. - After that if the
http://localhost:8080/url is checked in the browser the fetched data is displayed:
Conclusion
It was quite easy to get started with Deno. I find it very convenient that it supports TypeScript out of the box. Having the same programming language on frontend and backend side has several benefits, for example in my PoC, I was able to use the same Dto to represent the transferred object.
It would be great to use the same input validation code on frontend and backend side. Do you have any tips or best practices for that? Please let me know. :)
There is a post that continues this topic with setting up the development tools on this stack.
Oldest comments (1)
有什么不一样吗?你用ng build --prod打包出来了html,然后就用deno的server模式托管html?