Node Nx Tutorial - Step 2: Display todos

Great! you now have a server application set up to show some data when going to the /api route.

Next, you're going to add a new service, and set up some server side templates.

Creating a todos service

With Nx, you have the ability to scaffold out new code for your application. Create a Todos service and populate some todos!

Run nx generate @nrwl/nest:service todo --project todos --directory app to generate our new service

$ nx generate @nrwl/nest:service todo --project todos --directory app
CREATE apps/todos/src/app/todo/todo.service.spec.ts (453 bytes)
CREATE apps/todos/src/app/todo/todo.service.ts (89 bytes)
UPDATE apps/todos/src/app/app.module.ts (318 bytes)

Services are not the only things that the @nrwl/nest plugin can create. Run nx list @nrwl/nest to see other capabilities that the plugin provides.

Open the newly created file in apps/todos/src/app/todo/todo.service.ts and paste the following code:

1import { Injectable } from '@nestjs/common';
2
3export type Todo = {
4  message: string;
5  done: boolean;
6};
7
8const todos: Todo[] = [
9  { message: 'Take out trash', done: false },
10  { message: 'Continue using Nx', done: false },
11];
12
13@Injectable()
14export class TodosService {
15  getTodos(): Todo[] {
16    return todos;
17  }
18}

Usually services should call some kind of data source (like a database or even a file) but for this tutorial, just populate todos manually.

You now have your Todos service ready!

Install template engine

In order to render some views, you need to install a template engine:

yarn add hbs

or

npm install --save hbs

Once the installation process is complete, you need to configure the main.ts file with the following code:

1import { Logger } from '@nestjs/common';
2import { NestFactory } from '@nestjs/core';
3import { NestExpressApplication } from '@nestjs/platform-express';
4import { join } from 'path';
5
6import { AppModule } from './app/app.module';
7
8async function bootstrap() {
9  const app = await NestFactory.create<NestExpressApplication>(AppModule);
10
11  app.setBaseViewsDir(join(__dirname, 'assets', 'views'));
12  app.setViewEngine('hbs');
13
14  const port = process.env.PORT || 3333;
15  await app.listen(port, () => {
16    Logger.log('Listening at http://localhost:' + port);
17  });
18}
19
20bootstrap();

You added configuration for setting up the view engine, and removed the globalPrefix option.

Template rendering

Under the assets directory of the todo's project, you create a views directory with an index.hbs file inside with the following content:

1<!DOCTYPE html>
2<html>
3  <head>
4    <meta charset="utf-8" />
5    <title>App</title>
6  </head>
7
8  <body>
9    <ul class="todos">
10      {{#each todos}}
11      <li><input type="checkbox" {{#if done}}checked{{/if}} /> {{message}}</li>
12      {{/each}}
13    </ul>
14  </body>
15</html>

Next, update the app.controller.ts file with the following:

1import { Controller, Get, Render } from '@nestjs/common';
2
3import { AppService } from './app.service';
4import { TodosService } from './todos/todos.service';
5
6@Controller()
7export class AppController {
8  constructor(
9    private readonly appService: AppService,
10    private todosService: TodosService
11  ) {}
12
13  @Get('api')
14  getData() {
15    return this.todosService.getTodos();
16  }
17
18  @Get()
19  @Render('index')
20  root() {
21    return {
22      todos: this.getData(),
23    };
24  }
25}

You changed the @Get decorator for the getData function to point to the api route. You also changed this to call the todosService.getTodos() method.
Then you added the root function which renders the index file from our views directory.

The serve process should still be running. If it isn't, restart the process with nx serve todos

What's Next