wissel.net

Usability - Productivity - Business - The web - Singapore & Twins

Deploying a Single Page Application using the Domino REST API


The Domino REST API not only provides secure access to "jsonified" Domino data,
but also comes with capabilities to ease integration. This enables one to quickly cater to the long tail of applications, giving them a home instead of loosing them to the shadow IT.

Once you know the steps, you can deploy new Single Purpose Applications (I modified the meaning of SPA a little) in no time.

No CORS, no headache

DRAPI allows to host static applications in the keepweb.d directory. "Static" might be a little misnomer (it only relates to the source files, not the interaction) since a JS file can make your experience quite interactive. Since you run on the same Domain and port as the API, you don't need to worry about CORS

Preparation

Your SPA will live in a sub directory of keepweb.d, so think about a name, we shall use demo42 here. Add a suitable icon (e.g. 72x72 px png), name it demo42.png and you are ready to roll. Let's assume our Domino API is running on https://api.demo.io

Work faster with vitejs

viteJS is one of the fronteand tools you want to learn. It features "hot module reload" to speed up development and, when done, packages your application nice and tidy.

It is easy to get started. You need a current version (22.x at time of writing) of nodeJS installed as development tooling.

npm create vite@latest demo42 -- --template vanilla
cd demo42
npm install

This will create the demo42 directory and scaffold the project for you. Before we get started with athe development, let's adjust the environment. In the root of the project create a file vite.config.js

import { defineConfig } from 'vite';

export default defineConfig({
  base: '/keepweb/demo42/',
  server: {
    proxy: {
      '/api': {
        target: 'https://api.demo.io',
        changeOrigin: true
      }
    }
  }
});

This allows you to develop in the comfort of your local machine's hot module reload which refreshes your app on svae automagically. It also fixes the path matching to its final destination. Next create in public the file manifest.json. This file defines the tile layout for the landing page.

{
  "short_name": "Demo 42",
  "name": "The final answer to all Demos",
  "start_url": ".",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#aacccc",
  "icon": "vite.svg"
}

You can play with colors and icons as you deem fit. Now we are ready to run the application:

npm run dev

Your application will be available on http://localhost:5173/keepweb/demo42. As you can see, the html source code isn't polluted with JavaScript. The vanilla JS example is a little overengineered, the html in main.js could very well live in index.html, so I replace the content of main.js with this:

/* (C) 2025 - copyright holder, License */

// Constants

/* Login goes here */
const formLogin = () => {
  let username = document.getElementById('username-input').value;
  let password = document.getElementById('password-input').value;
  login(username, password);
};

const login = (un, pwd) => {
  fetch('/api/v1/auth', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ username: un, password: pwd })
  })
    .then((response) => response.json())
    .then((json) => extractCredentials(json))
    .catch((err) => console.error(err));
};

const extractCredentials = (json) => {
  if (json.bearer) {
    let bearer = json.bearer;
    window.bearer = bearer;
    statusMsg('Login successful');
    document.getElementById('credentials').style.display = 'none';
    document.getElementById('someid').style.display = 'block';
    doSomeWork();
  } else {
    statusMsg('Login failed');
  }
};

const doSomeWork = () => {
  statusMsg('Here shall be dragons');
};

const statusMsg = (statusText) => {
  document.getElementById('message').innerHTML = statusText;
};

/* Bootstraping */
const bootstrap = () => {
  const login_button = document.getElementById('login-btn');
  if (login_button) {
    login_button.addEventListener('click', formLogin);
  } else {
    statusMsg('No Login avilable');
  }
};

// Keep this at the bottom, so all functions are loaded
if (document.readyState != 'loading') {
  bootstrap();
} else {
  document.addEventListener('DOMContentLoaded', bootstrap);
}

Of corse, when you plan multiple small apps, you would extract common functions into a module.

My HTML looks like this:

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Demo 42</title>
    <link rel="stylesheet" href="src/index.css" />
  </head>
  <body>
    <div class="container">
      <header>
        <h1>Demo 42 Application</h1>
      </header>
      <main>
        <section class="outline" id="credentials">
          <form id="credentials-form">
            <p>
              <label for="username-input">User Name</label>
              <input type="text" id="username-input" />
            </p>
            <p>
              <label for="password-input">Password</label>
              <input type="password" id="password-input" />
              <button id="login-btn" type="button">Login</button>
            </p>
          </form>
        </section>
        <section class="outline" id="someid">
          <!-- Application specific code goes here -->
        </section>
        <section>
          <form id="message-box">
            <div disabled class="flex3" id="message">Status</div>
          </form>
        </section>
      </main>
      <footer>&copy; 2025 Copyright holder</footer>
    </div>
    <script type="module" src="src/index.js"></script>
  </body>
</html>

That's all it takes (We get to API calls in another blog entry) to get started. Once you are happy with the results,
it is timme for deployment.

# create a dist directory with production ready code
npm run build
# Move it to Domino, might differ for your environment
scp -R dist/* domino@api.demo.io/local/notesdata/keepweb.d/demo42/

As usual YMMV


Posted by on 17 March 2025 | Comments (2) | categories: Domino DRAPI WebDevelopment

Comments

  1. posted by Pantelis Botsas on Tuesday 18 March 2025 AD:

    Thank you very much for this blog post, Stephan. As I am very fond of the Vue-Framework, I already knew the "specials" about Vite (french for quick/fast).

    A lot of HCL developers and also some distinct Domino developers have been saying for over a decade that one should also take a closer look at the front-end frameworks. The reality out there for individually developed software under Domino is still aimed at the Notes client. No matter how limited the functionality is. No matter how cruelly the users are tortured with duplicate chains of action. What has been built this way for 20 years will continue to be built this way for the next 20 years.

    The insight into many developer teams from the Domino world scares me. I often get the impression that they are stuck somewhere in the 80s and autistically ignore the conveniences that have emerged in the Domino landscape in recent years.

    Classes in LotusScript? Not known!
    Web services that respond to different request types? Not necessary - also possible with LotusScript agents!
    Usability of input forms? Why are we discussing this? In the Notes client we also have 482 fields in the form and 36 actions that are always visible!

    I am now starting my fourth attempt to explain the basics of a web-based application to a long-established Notes development team. I don't want to take anything away from anyone. The people who want to let off steam with the backend can continue to do so in their beloved LotusScript bubble.

    But ... I am tired!

    Every argument as to why it is more expedient in the long term to optimize data quality in the backend and provide targeted REST APIs in order to handle data sparingly is immediately dismissed by the fact that this has not been taken care of so far. But it is surprising for them why the applications react so pathetically slowly.

    If you suggest that the design of the application should be decoupled from the backend development in order to optimize data storage and data presentation more independently, the die-hard Notes developers turn away in a huff because a “NodeJS framework fiddler” is now supposed to take over the design of their beloved Notes client user interface, which then does not look very Notes client-y on the web now. However, they themselves do not even want to begin to familiarize themselves with the “web languages”.

    I am struggling with myself here whether it might be easier to turn my back on the domino world after all. I don't want to wait another 20 years for the realization that users no longer want meaningless complexity in the application interface.


  2. posted by Paul Withers on Tuesday 18 March 2025 AD:

    While developing locally, you’ll still hit CORS problems. DRAPI docs have easy steps for enabling localhost, in lab 11 of the capability walkthrough tutorial, which of course you’ve already done! Or you can develop against mock data, so you’re not hitting the DRAPI server until you deploy.