We often come across a requirement that we need to generate a dynamic HTML template but with minimalistic code and without having any different UI components, To achieve that we need to have a sophisticated way to do that, and to summarize that we can conclude in the below statement

Template engines are the backbone of web development, providing a powerful and flexible way to create dynamic web pages. NestJS makes it easy to integrate your favorite template engine, allowing you to focus on building your application’s logic instead of worrying about the nitty-gritty details of rendering HTML. With NestJS and your preferred template engine, you can create beautiful and functional web pages that delight your users and keep them coming back for more – ChatGPT

So, NestJS is a powerful framework for building scalable and maintainable server-side applications in Node.js. One of the features that NestJS offers is support for template engines, which allow you to generate dynamic HTML content for your web pages. A template engine is a tool that lets you create HTML templates that contain placeholders for dynamic content. These placeholders are replaced with actual content at runtime, allowing you to generate dynamic HTML content on the server.

Pre-requisite

Install the package and create a project as mentioned below in the code snippet

$ npm i -g @nestjs/cli
$ nest new nestJsTemplate
$ cd nestJsTemplate
$ nest generate module reports
$ nest generate controller reports
$ nest generate service reports

So far you have created the project and template artifacts, now below are the steps to mentioned code snippet which you need to implement to build the nestJsTemplate

Code Implementation Steps

1st we are going to write the controller class as mentioned in the code snippet for ReportsController.ts class

import { Controller, Get, Param, Res } from '@nestjs/common';
import { ReportsService } from './reports.service';
import * as empData from 'src/data/sample.json';//static json file
import { Response } from 'express';

@Controller('reports')
export class ReportsController {
    constructor(private reportsService: ReportsService) { }
    @Get()
    getEmployeeReports(): any {
        // return [{id : 0}];
        return this.reportsService.findAll();
    }

    @Get(':id')
    getEmployeeReportsById(@Param('id') id: string): any {
        return this.reportsService.findById(id);
    }

    @Get('emp/:id')
    async getEmpReports(@Param('id') empId: string): Promise<Object> {
        var report = empData;
        return report;
    }

    @Get('emps/:id') // method to process the html template content
    async getEmpReportsAsTemplate(@Param('id') empId: string, @Res() res: Response) {
        var report = empData;
        return res.render(
            "report.hbs", { emp: empData.employeeDtls, dept: empData.departments },
        );
    }

}

Listing 1.1: Code snippet for the controller class

As you can see in the above code snippet (Listing 1.1),  It has four methods out of which 1st three are the normal method to fetch the employee Id and getAll Employees’ details and provide the response in JSON format, once you try to execute the API.

But for the last method, if you observe that we had file name “report.hbs”, we are going to define the code snippet. and this method is used to read the static file content as we defined the JSON static information, which we are reading in this method and assigning to the object, and the same object if we can observe is being used in the report.hbs file as shown below

 

<body>

    <h1>Employees - Reporting Info</h1>
    <table id="reports">
        <tr>
            <th>Employee Id </th>
            <th>First Name </th>
            <th>Last Name </th>
            <th>email </th>
            <th>Hired Date</th>
        </tr>
        {{#each emp}}
        <tr>
            <td>{{employeeId}}</td>
            <td>{{firstName}}</td>
            <td>{{lastName}}</td>
            <td>{{email}}</td>
            <td>{{hireDate}}</td>
        </tr>
        {{/each}}
    </table>

    <h2>Department Details</h2>
    <table id="reports">
        <tr>
            <th>Department Id </th>
            <th>Department Name </th>
            <th>Email </th>
            <th>Department Manager </th>
        </tr>
        {{#each dept}}
        <tr>
            <td>{{id}}</td>
            <td>{{deptName}}</td>
            <td>{{email}}</td>
            <td>{{departmenttManager}}</td>
        </tr>
        {{/each}}
    </table>
</body>

Listing 1.2: Code snippet of report.hbs file

Here we are writing only the code snippet and to know the other content, you can refer to the git link, which I would share at the end of this blog.

Now if you observe here in the <#each> tags there are emp and dept variables, which are assigned to the object in the controller method “getEmpReportsAsTemplate

Now, the dynamic HTML and method are defined, we need to define the settings, which should do the actual magic and this is happening in the main.ts file, for which the code snippet is shown below

import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { NestExpressApplication } from '@nestjs/platform-express';
import { resolve } from 'path';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(
    AppModule);

  app.useStaticAssets(resolve('./src/public'));
  app.setBaseViewsDir(resolve('./src/views'));
  app.setViewEngine('hbs');
  app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
  app.setGlobalPrefix('api/v1');

  await app.listen(process.env.PORT || 3000);
}

bootstrap();

Listing 1.3: Code snippet of the main module file

In the above code, we are settings the views and defining from where it has to read the hbs file and importing the platform-express library, which basically helps in rendering the HTML content in the browser.

Along with that, the sample JSON that we are using to render in UI can be shown below

{
    "employeeDtls": [
      {
        "employeeId": 100,
        "firstName": "John",
        "lastName": "Chen",
        "email": "john.chen@###.com",
        "hireDate": "2008-10-16"
      },
      {
        "employeeId": 101,
        "firstName": "Ameya",
        "lastName": "Job",
        "email": "ameya.job@$###.com",
        "hireDate": "2013-03-06"
      },
      {
        "employeeId": 102,
        "firstName": "Pat",
        "lastName": "Fay",
        "email": "pat.fey@###.com",
        "hireDate": "2001-03-06"
      }
    ],
    "departments": [
      {
        "id": "1",
        "deptName": "Payroll",
        "email": "payroll@###.com",
        "departmenttManager":"Adam Liser"
      },
      {
        "id": "2",
        "deptName": "Admininstrator",
        "email": "admin@###.com",
        "departmenttManager":"Riner Saw"
      }
    ]
  }

Listing 1.4: JSON sample data

 

Deployment to BTP

To deploy to BTP, 1st we need to follow the below pre-requisite steps as mentioned below

So far, we developed and run the application to test how API works locally, Now you going to test the same list of API testing by deploying it to the SAP BTP. To proceed with the employeedtsApp app deployment there are a few pre-requisite steps, which we need to follow step by step as mentioned below

  1. Creation of a trial account on SAP BTP: Login to SAP trial account and create an account, dev space as mentioned in (https://developers.sap.com/tutorials/hcp-create-trial-account.html)
  2. Installation of Cloud Foundry CLI: refer to the documentation to install the cf cli in your laptop and in case of MAC-OS install use the command brew install cloud foundry/tap/cf-cli@8 by running it in your laptop terminal you can refer to the official documents of SAP for CF-CLI installation link ( https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/4ef907afb1254e8286882a2bdef0edf4.html).
  3. Installation of MultiApps CF CLI plugins: Install the multi-app cf cli as mentioned in the git link (https://github.com/cloudfoundry/multiapps-cli-plugin).Installation of cloud MTA Build tool: Follow the link (https://sap.github.io/cloud-mta-build-tool/download/) to install the MTA build tool to build a mta archive project which we can be used as a compiled file that will be deployed to already created developer space in SAP BTP.
  4. Modification of mta.yml file: As this is a typescript-based application, you need to modify the .yml, so that the application can be deployable to the SAP BTP dev space, so below Listing 1.5 which contains the code snippet of mta.yml also shown in the Figure 1.10, if you noticed below in the mta.yml file we have added as custom commands which are specific to typescript based application, it helps to build the application before deploying the application into SAP BTP dev space.
_schema-version: 3.3.0

ID: my-sample-nestjs
version: 0.0.1

modules:
  - name: my-sample-nestjs
    type: nodejs
    path: .
    build-parameters:
      builder: custom
      commands:
        - npm ci
        - npm run build
        - npm prune --include=dev
    parameters:
      buildpack: nodejs_buildpack
      command: node dist/main
      memory: 128M
      routes:
        - route: my-sample-nestjs-${space}.${default-domain}
        - route: my-sample-nestjs-${space}.cert.${default-domain}

Listing 1.5: Code snippet of mta.yml file

Now to build and deploy the application execute the below statement in terminal

$ cf login
$ mbt build -t ./  
$ cf deploy my-sample-nestjs_0.0.1.mtar  

Listing 1.6: Command to build and deploy the app in SAP BTP

 

Result/Output

Now Navigate to the browser, after the successful deployment of the application to view the output, Since all the API calls are GET, So we can run it in the browser itself.

Fig-1: API response screenshots

As you can see in the above Fig-1, we are able to generate the employee info in the form of a table, which is again HTML content, and that too we did not have any specific Ui component to do in the UI. In this way, we can render any HTML content in the browser. The API ends points which are set in the main.ts file as “/api/v1/reports/emps/1”. If you notice, we tried to populate two sets of tables, one with the employee info and the other with the employee info, So that we can understand how we have a different set of data that can be shown in the UI.

 

Conclusion

NestJS is a powerful and flexible framework for building scalable and maintainable server-side applications. One of the key strengths of NestJS is its support for a variety of template engines, including Handlebars, EJS, Pug, and more. With the ability to easily integrate these engines into your NestJS application, you can create beautiful and dynamic web pages that engage your users and help your business grow. Whether you’re building a small prototype or a large-scale enterprise application, NestJS and its template engine ecosystem have got you covered. With the above example, you can somehow be able to build the template based HTML content

GIT nestJsTemplate

 

Suggestions and feedback are welcome !!!

 

 

Sara Sampaio

Sara Sampaio

Author Since: March 10, 2022

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x