Htmx and NestJS a quick overview
Tags: webdev, programming, tutorial, javascript
Published: 2024-01-21 22:48:26

I've have noticed on tech social media and looks like HTMX is a popular topic nowadays, so I decided to give it a try on the weekend to experiment with some basics.

###Stack setup
For the backend [Nestjs](https://nestjs.com/) framework for NodeJS applications, I like the patterns they promote. I have used this sample from the docs as base for my demo, it uses [handlebars](https://handlebarsjs.com/) a template engine [nestjs-mvc-fastify](https://github.com/nestjs/nest/tree/master/sample/17-mvc-fastify)

The UI is built with [Bulma](https://bulma.io/), since I wantend to avoid the setup of clunky frontend frameworks, so we can focus a bit on simplicity, I'm using the CDN links/sources at the moment, please check their websites for the latest versions of the CDN resources.

Please check the [htmx.org](https://htmx.org/) docs they are pretty neat!

----

First thing that comes to my mind is how to do routing with HTMX? Well you don't have to use any magic routing library or complex implementation, basically if you are running a server side implementation that renders HTML with a web framework that supports http routing.

But there's an interesting feature in htmx using the http routing approach:

`hx-boost`

from their documentation 

> The hx-boost attribute allows you to “boost” normal anchors and form tags to use AJAX instead. This has the nice fallback that, if the user does not have javascript enabled, the site will continue to work.

Pretty neat right! so you will have some similar experience to those fancy routers for React, btw I believe saw similar implementation before called Turbolinks well that's olds news.


So basically you can have some regular HTML links and every time you click on this link instead of doing a full page refresh it will swap the content of the page dynamically.

```html
<nav hx-boost="true">
      <a class="navbar-item" href="/about">
        About
      </a>
      <a class="navbar-item" href="/polling">
        Polling
      </a>
</nav>
```

In our NestJS server we will create this routes to serve some boring HTML, 

Let's continue with another feature, it's not that popular nowadays to do polling but can be useful for long tasks without using a WebSocket.

Ok let's check the backend in our app.controller.ts 
I'll create a base for our apis and polling page.
please take a close look in the comments.

```ts
import { Get, Controller, Render, Redirect, Res } from '@nestjs/common';

@Controller()
export class AppController {
  pollingCount = 0;
  @Get('/')
  @Render('pages/index.hbs')
  root() {
    return null;
  }

  // Our polling endpoint.
  @Get('/polling')
  @Render('pages/polling.hbs') // how we render the page
  pollingPage() {
    return {layout: true, authenticated: this.authenticated};
  }

  @Get('api/polling')
  @Render('api/polling.hbs') // We need to return HTML content 
  apiPolling(@Res() res) {
    this.pollingCount++; // simple increment of polling count
    if (this.pollingCount > 10) { 
      // HTTP response code 286 and the element will cancel the polling - HTMX docs
      res.status(286);
      this.pollingCount = 0;
    }
    const date = new Date().toUTCString();
    // We should return the states for the handlebar template
    return {time: date, pollingPercent: this.pollingCount * 10};
  }

}

```

### HTML Page for polling
We are going to define a page in our handlebars templates, this will contains some special attributes

`hx-get, hx-trigger, hx-swap`

hx-get will go to our api polling and will bring the content then it will be trigger by hx-trigger every 1s this is quite explicit in HTMX and will be using hx-swap that will perform the update for that piece of HTML, 


```html
// views/pages/polling.hbs
<div class='box'>
  <div hx-get='api/polling' hx-trigger='every 1s' hx-swap='innerHTML'>
    <h3>Waiting for poll responses...</h3>
  </div>
</div>

```

How our API response should look? well it should be the HTML that we want to place in our innerHTML right,

This piece of code as you can see it's just receiving the variables from our api/polling this will pass the pollingPercent and the dateTime to our handlebar template `{{datetime}}` `{{pollingPercent}}`

```html
// views/api/polling.hbs
<article class='message is-link' id='message-clicked'>
  <div class='message-header'>
    <p>Time stamp {{datetime}}</p>
  </div>
  <div class='message-body'>
    We are pulling this from a request to the service api/polling check network.

    <progress class="progress is-primary" value="{{pollingPercent}}" max="100">{{pollingPercent}}%</progress>
  </div>
</article>

```

After this implementation this will give us some nice animation with the progress bar being filled up with the percentage.

## Conclusions

HTMX seems to be a refreshing frontend solution and old-school a the same time, if you see the only JavaScript code we wrote is on the server side NestJS mainly creating the API's and rendering HTML, 

From my point of view this can be a good solution for web applications that implements the Backend for Frontend pattern, you can probably avoid a lot of work maintaining complex frontend framework and backend at the same time, 

One of the possible downsides is when you plan to use your backend API's for other platforms like Mobile Apps then you definitely need to look in to JSON API first or GraphQL, and then create an extra layer for HTMX that serves HTML, hmmm.

But overall first good impression of this eloquent frontend solution using HTML and attribute to build complex UIs. 

Please let me know your thoughts about it. I'm planning to continue with more features.

---  

Live demo here:
[Demo - nestjs-htmx.vercel.app](https://nestjs-htmx.vercel.app/) running on Vercel for simplicity

If you want to play around you can find this project code here.
Github: [https://github.com/diegochavez/nestjs-htmx](https://github.com/diegochavez/nestjs-htmx)

If you want to reach me you can follow me on [X - Twitter @diegochavez](https://twitter.com/diegochavez)


 Thanks for reading! please let me know your thoughts.