Home Angular Angular 9 Angular 9 NgRx Data and NestJS

Angular 9 NgRx Data and NestJS

Today we will explore the way to connect a simple NestJS server with the latest Angular NgRx Data.

NestJS server

Many people already talked about this project, I won’t add too much, but the pros that I see in NestJS are :

  • Code architecture based on Angular-like structure, with Modules and TypeScript.
  • Abstraction of NodeJS Express, and a very easier approach.
  • Spring-like decorators, a rich API to build all common features in a web server.
  • GraphQL ready.
  • Microservices, websockets …

We won’t cover the database aspect here, my focus will be on how to build a very simple project, yet clean (I hope) as a starting point. But that’s a good thing, we will be able to expose a CRUD API with no database, but still it will be working.

Angular workspace

As many of you know, we entered the age of workspaces for Angular projects. One of the other names for that would be monorepo. The reasons for that would be multiple :

  • Handle multiple applications with the same version and have the upgrades much much easily than having to do so in each and every app.
  • Start building libraries and share code among our Angular apps ecosystem.

Also, Nx uses great modern tools like Cypress for e2e testing and Jest for unit test, and I love that.

Note : you don’t need Nx to organize your project, it will be simply a little bit faster here.

https://nx.dev/angular/getting-started/nx-and-cli

Angular Universal

It is worth to mention that a similar approach exists by runnning the NestJS backend with Angular Univeral, but we won’t cover that 🙂

https://github.com/nestjs/ng-universal

The project

You actually have many options to create the project, have an empty project and then add a frontend with Angular and a backend with NestJS. The installer will prompt you anyway for common stacks :

npx create-nx-workspace todosws

Choosing the full-stack option will scaffold 3 projects (4 with the e2e one) :

  • Angular application in /apps/todosws
  • NestJS application in /apps/api
  • Shared code api library in /libs/api-interface

Run both backend and frontend :

ng serve todosws // first cli
ng serve api // second cli

Note that the Angular app can call the NestJS server on a different port because it’s using a proxy.conf.json that was built by Nx for you :

// /apps/todosws/proxy.conf.json
{
"/api": {
"target": "http://localhost:3333",
"secure": false
}
}

Now, of course we will want to add a CRUD api to the back, and get rid of direct HTTP calls in the app.component.ts :

// app.component.ts
export class AppComponent {
hello$ = this.http.get<Message>('/api/hello');
constructor(private http: HttpClient) {}
}

Build the server API with NestJS

We will generate a module for our API, it’s not mandatory, but could be seen as a good practice 😉 You can use your Angular Console for using / discovering all the nest shematics, I love the work they did ! Your can use ng generate command or the @nestjs/cli (don’t forget to install it globally).

Note : be careful when running nest cli commands, you might need to be in the proper folder or specify the right path.

PS D:\tests\nx\todosws\apps\api> nest g mo Todo app
CREATE /src/app/todo/todo.module.ts (81 bytes)
UPDATE /src/app/app.module.ts (308 bytes)

Then we need a service and a controller.

PS D:\tests\nx\todosws\apps\api> nest g co todo app
CREATE /src/app/todo/todo.controller.spec.ts (479 bytes)
CREATE /src/app/todo/todo.controller.ts (97 bytes)
UPDATE /src/app/todo/todo.module.ts (166 bytes)PS D:\tests\nx\todosws\apps\api> nest g s todo app
CREATE /src/app/todo/todo.service.spec.ts (446 bytes)
CREATE /src/app/todo/todo.service.ts (88 bytes)
UPDATE /src/app/todo/todo.module.ts (240 bytes)

Nest server is in watch mode, so you can see that the server route is prepared, because the controller is declaring a /todo route :

But if you test the route, it will fail, since there is no decorator for any HTTP method. Lest’s add a route in the controller with mock objects :

export class Todo {
id: number;
title: string;
}
export const todos: Todo[] = [
{ id: 0, title: 'Discover NgrX Data' },
{ id: 1, title: 'Test new IronMan armor' }
];
@Controller('todo')
export class TodoController {
@Get()
findAll(): Observable<Todo[]> {
return of(todos);
}
}

Let’s add the class (yes, NestJs requires a class and not an interface) and the mock to the library, this way we will be able to use it in the Angular app as well. Feel free to organize your lib a little bit better than these ugly exports 🙂

Now the controller looks like that :

import { Todo, mockTodos } from '@todosws/api-interface';
@Controller('todo')export class TodoController {
@Get()
findAll(): Observable<Todo[]> {
return of(mockTodos);
}
}

Now, we will give the service the responsability to handle the data, let’s create all methods we see usefull :

@Injectable()
export class TodoService {
private todos: Todo[] = [];constructor() {
this.todos = mockTodos;
}create(todo: Todo) {
this.todos.push(todo);
}findAll(): Todo[] {
return this.todos;
}find(id: number): Todo {
return this.todos.find(item => {
return item.id == id;
});
}remove(id: number): void {
this.todos = this.todos.filter(item => {
return item.id != id;
});
}update(id: number, todo: Todo): Todo {
const tmpIndex = this.todos.findIndex(obj => obj.id == id);
const updatedObject = { ...this.todos[tmpIndex], ...todo };
this.todos = [
...this.todos.slice(0, tmpIndex),
updatedObject,
...this.todos.slice(tmpIndex + 1)
];
return updatedObject;
}
}

Let’s add the other routes to the controller, that will simply manipulate the Todos via the service, nothing fancy really.

@Controller('todo')
export class TodoController {
constructor(private todoService: TodoService) {} @Get()
findAll(): Observable<Todo[]> {
return of(this.todoService.findAll());
} @Get(':id')
findOne(@Param('id') id): Observable<Todo> {
return of(this.todoService.find(id));
} @Post()
async create(@Body() todo: Todo) {
this.todoService.create(todo);
return todo;
} @Put(':id')
update(@Param('id') id: number, @Body() updateTodo: Todo): Observable<Todo> {
return of(this.todoService.update(id, updateTodo));
} @Delete(':id')
async remove(@Param('id') id: number): Promise<void> {
return this.todoService.remove(id);
}
}

Now all the routes should be active and we could test them with whatever way, postman for example. Note that the controllers will be enhanced later with all NestJS tools, like middlewares, exceptions, filters …

This is indeed a very very simple API, but it seems to work, as I said, we won’t cover database tools, maybe some other time, and you might find other articles about that.

Add swagger on NestJS

This is a very simple step as described here. I alter the configuration a little bit, since /api is the base for REST endpoints, I use /swagger for this tool.

// define setBasePath() so swagger UI can run tests against /api
const options = new DocumentBuilder()
.setTitle('Todo API')
.setDescription('The todo API description')
.setVersion('1.0')
.addTag('todo')
.setBasePath('api')
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup('swagger', app, document);

We can test now Swagger UI on http://localhost:3333/swagger/#/

Add Logger Middleware

By default, NestJS doesn’t come with a logger, but it’s easy to implement, following this doc. You can track precisely any route or all routes, and check how the server is called.

PS D:\tests\nx\todosws\apps\api> nest g mi common/logger app
CREATE /src/app/common/logger.middleware.spec.ts (188 bytes)
CREATE /src/app/common/logger.middleware.ts (198 bytes)// app.module.ts
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggerMiddleware).forRoutes('todo');
}
}

Then you can alter your logger the way you want :

export class LoggerMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: Function) {
console.log('request : ' + req.method + ' - ' + req.url);
next();
}
}// logging :
[Nest] 17228 - 2019-07-11 2:51 PM [NestApplication] Nest application successfully started +5ms
Listening at http://localhost:3333/api
request : GET - /
request : GET - /
request : PUT - /3

Install NgRx Data

We will do as “usual” for NgRx, and then add NgRx Data, since it relies on the following libs : store, effects and entity

npm install @ngrx/schematics --save-devnpm install @ngrx/store @ngrx/effects @ngrx/entity @ngrx/data @ngrx/store-devtools --save

Check the steps here for a starter : https://medium.com/@coco.boudard/starting-with-angular-and-ngrx-store-75e92c90d346

We can add @ngrx /data with the command add (it’s already installed, but it will ad an import line in the main module) :

PS D:\tests\nx\todosws> ng add @ngrx/data
Skipping installation: Package already installed
UPDATE package.json (2340 bytes)
UPDATE apps/todosws/src/app/app.module.ts (640 bytes)

We need to update the app.module to have the mandatory tools : @ngrx/effects and @ngrx/store :

StoreModule.forRoot([]),
EffectsModule.forRoot([]),
!environment.production ? StoreDevtoolsModule.instrument() : [],
EntityDataModule.forRoot(entityConfig)

The entityConfig can look as follows, very simple, with a simple modification : the plural name for the entities (later we will add specifics like a filter or other https://ngrx.io/api/data/EntityCollection#filter).

// store/entity-metadata.ts
const entityMetadata: EntityMetadataMap = {
Todo: {}
};// because the plural of "todo" is not "todos" by default in Nest
const pluralNames = { Todo: 'Todo' };
export const entityConfig = {
entityMetadata,
pluralNames
};

This is it for the configuration, now we need an Angular service that implements NgRx Data, for example, EntityCollection :

export class TodoService extends EntityCollectionServiceBase<Todo> {
constructor(serviceElementsFactory: EntityCollectionServiceElementsFactory) {
super('Todo', serviceElementsFactory);
}
}

In the component, all we need to do it to call the service getAll() method and observe some of its attributes, like count$ :

counter$: Observable<number>;
constructor(private http: HttpClient, private todoService: TodoService) {
this.counter$ = todoService.count$;
}
ngOnInit(): void {
this.todoService.getAll();
}

And display the counter in the template :

<div>
<span [innerText]="counter$ | async"></span>
</div>

Finish the screens

The final app will have a few components to list the Todos and make simple operations. Just like the original app I made.

Pretty the application

We will simply add bootstrap 4 and fontawesome with angular-fontawesome, elegant way to load only needed icons.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -

Most Popular

Auto Detect Responsive Screen Sizes in Angular

Most of the time, we use CSS media queries to handle responsive, screen size changes to layout our content differently. However, there...

Angular 9 CRUD | Part 8 |Delete an Existing Product

In this article, I am going to show you how to delete a product. Create a method...

Angular 9 CRUD | Part 7 | Update an Existing Product

In this article, we will update the existing product details. Here we are using reactive forms and HttpClient for updating the...

Angular 9 CRUD | Part 6 | Create New Product

In this article, we will create a new product. Here we are using reactive forms for creating a new product. first...

Recent Comments

Sathish Kumar Ramalingam on Angular 2 Admin LTE Theme Integration