gohtmxgo-fiber

No DOM update with HTMX and GoLang


I'm trying to learn HTMX with Go and GoFiber.

Here is my HTML page :

<script src="https://unpkg.com/htmx.org@2.0.0" integrity="sha384-wS5l5IKJBvK6sPTKa2WZ1js3d947pvWXbPJ1OmWfEuxLgeHcEbjUUA5i9V5ZkpCw" crossorigin="anonymous"></script>
<main>
    <div class="grid h-screen place-items-center">
        <div class="flex flex-col items-center space-y-4">
            <h1 class="text-5xl font-bold mb-16">Connexion</h1>
            <form hx-post="/auth" hx-target="#error-message" hx-swap="innerHTML" class="flex flex-col items-center space-y-4">
                <input
                    type="password"
                    placeholder="Mot de passe"
                    class="input input-bordered input-primary w-full max-w-xs"
                    id="password"
                    name="password"
                />
                <button type="submit" class="btn btn-primary">Connexion</button>
            </form>
            <div id="error-message" class="text-red-500"></div>
        </div>
    </div>
</main>

and here is the /auth route of my API in GoFiber

func Auth(c *fiber.Ctx) error {
    // get the password on the body
    clientPassword := c.FormValue("password")

    // check if the password is correct
    password, err := database.GetPassword()
    if err != nil {
        log.Fatalf("Failed to get the password: %v", err)
        return c.Status(fiber.StatusInternalServerError).SendString("Internal Server Error : cannot get the password in db")
    }

    if clientPassword != password {
        log.Println("Incorrect password")
        return c.Status(fiber.StatusUnauthorized).SendString("<p class='text-red-500'>Incorrect password. Please try again.</p>")
    }

    log.Println("Correct password")

    // redirect the client on the home page
    return c.Redirect("/videos")
}

My problem is that when I send an incorrect password, the API correctly receives the request and my browser correctly receives the response with a status code of 401 and the HTML string. However, the message sent by the API does not appear in the error-message div. Why didn't it work, and how can I fix this?

(I tried swapping the outerHTML, targeting a class insted of an id but nothing seem to work.)


Solution

  • HTMX by default only processes successful requests. If you want to handle 401 responses, you have two basic choices. I would say up front that I am not a fan of using 401 for this purpose, I would use 422 instead which is "unprocessable entity". It is a better fit for what is essentially a validation type of error from the perspective of a login form. Your mileage may vary.

    Option 1: Use an extension library

    https://github.com/bigskysoftware/htmx-extensions/blob/main/src/response-targets/README.md

    If you use it, be aware that it is not enough to include the script in your page. You also need to activate it using hx-ext : https://htmx.org/docs/#extensions

    Example setup:

    <script src="https://unpkg.com/htmx-ext-response-targets@2.0.0/response-targets.js"></script>
    <body hx-ext="response-targets">
    
    <form hx-post="/auth" hx-target-422="#error-message"
    

    Option 2: Tell HTMX that it should process specific status codes

    Adding a whole different extension library just to get one task done might seem overkill; I wouldn't want to riddle my front end with large amounts of status-code specific target directives. Fortunately HTMX is quite configurable. You can tell it that you do want to "swap" on specific response codes. https://htmx.org/docs/#requests

    Example:

    document.body.addEventListener('htmx:beforeSwap', function(evt) {
      if(evt.detail.xhr.status == 422) {
        evt.detail.shouldSwap = true;
        evt.detail.isError = false;
      }
    });
    

    Rinse and repeat for any other error status codes you would want to handle in your front-end. Just keep in mind that if you start to put a long list of response codes here... you may want to rethink if you actually need HTMX for your use case.