wissel.net

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

Unless you have a Google size API problem use curl


A few days ago I posted on LinkedIn:

"Unless you have a Google/Meta/Antropic size API problem, I have a simple rule/insight:
Don’t create an api you can’t interact with using curl
".

I've been asked to elaborate.

The tool and the task

Firstly a remark about the tool, curl. It is an incredibly powerful tool with super flexible use cases. Just look at the list of supported protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS, WSS.

Understanding, even mastering it, is a must have for any developer (or admin for that matter).Want to fetch data unencumbered by CORS or CSP - curl is your friend.

You can read the sentence above also this way: Don't design an API if you. haven't mastered curl

Picking an API architecture is a big decision and there are quite many to pick from:

Here's the markdown source code:

Architecture Description
REST Uses HTTP methods to access and change resources through URLs. Robust well supported architecture with mature tooling. Easy to discoverm used for Web services, mobile apps or public APIs. Not suitable for real-time bidirectional communication or data transfer minimalism. Typically uses JSON payloads, previously XML, but will cater any data. Complex queries need to be handled in application logic. Really needs HTTP QUERY
RPC While REST is resource oriented, RPC is action oriented and is not limited to the HTTP(s) protocol. Typically you have a single endpoint where the posted payload determines the action. Examples are SOAP, JMAP, CORBA or propriarty protcols like in use with React Server Components
GraphQL Client requests exactly the data it needs using a query language, used in apps needing flexible data fetching, reducing over-fetching. Since the Query is clientside complexity is shifted to the client and security can be a nightmare. Sucks for caching or file uploads. Microsoft is a fan
SOAP (Simple Object Access Protocol) XML-based protocol with strict standards and built-in error handling. Unparalled accurate through WSDL definitions. Works well between unrelated parties, e.g. ebXML, heavy protocol, not popular in web applications anymore (despite giving AJAX its name)
gRPC (Google Remote Procedure Call) High-performance framework using Protocol Buffers. The data definitions are not transfered, like in XML or JSON, so data transfer is minimized, can transfer bucket loads of data. When you run trillions of requests, like Google, every bit counts. Severe limitation on discoverability, language support and tooling. Best used server to server
WebSocket Two-way communication channel over a single TCP connection used for Chat apps, live updates, real-time gaming, scaling is not for the faint of heart
Webhook Server sends automatic HTTP callbacks when events occur. Basically two way REST. Elegant and hard to test unless you can control the callback destination. Popular for payment notifications, automated workflows, CI/CD pipelines. Has special needs to make it traceable, no guaranteed delivery or real-time two-way communication
MQ (Message Queue) or MQTT (Message Queuing Telemetry Transport) Publish/subscribe messaging protocols, MQTT is suitable for low-bandwidth networks. Asynchronus processing of requests for loosely coupled systems. Very flexible but its store and forward principles require careful planning, especially around security and replay (keyword Idempotency)
Kafka Distributed streaming platform that handles high-volume data streams. In laymen's terms: a queue like MQ, with added transformation capabilities, persisten queue storage, suitable for really big volumes of data (just ask Uber about it). Fun to use, not fun to run (strongly advise hosted Kafka). Kafka is the big gun, it can solve your problem, in a lot of case like a shipping container can deliver a single pizza

Looking at the options (I'm sure there are more), you can see which ones can be covered by curl: REST, some RPC (when HTTP or SMTP based), GraphQL, SOAP, WebSocket, Webhooks (only to initialize). Eventually Kafka, when its http interface is active, but that's just http based RPC.

Compare the "Command Line Pain"™ when using curl to model a request (or process the result with jq). This gives you a data point you can add to your considerations which API to implement. It shouldn't be the only one: complexity, environment, data volumes, security etc. are equally important. The curl exercise helps to keep an eye on the tendency to overengineer.

As usual YMMV


Posted by on 31 December 2025 | Comments (0) | categories: API WebDevelopment

Higher Level Custom Events


A common occurence in web applications are button bars that execute various commands. So I was thinking of a pattern how to make this flexible and repeatable.

Separate Event and Actions

The typical setup we find is like:

const btn = document.querySelector('#myButton');
btn.addEventListener('click', (event) => {
  event.preventPropagation();
  // Business logic goes here
  doStuff();
});

This ties the logic to a low-level event of a low level component. To increase the usefulness we need to move from "mechanical" events to business level events, kind of.

An anology: imagine a fastfood kitchen. The cook gets orders "2 burgers, large fries" that don't contain: customer tapped on the order kiosk, drive thru order or delivery request. This information iss handled by the front-desk.

Similarly we can approach the button event. Instead tying our business logic to the click event, we tie it to a higher level event.

Components send events

const btn = document.querySelector('#myButton');
btn.addEventListener('click', (event) => {
  window.dispatchEvent(new CustomEvent('update-request', { detail: { button: btn }, bubbles: true, composed: true }));
});

This is oblivious where the business logic happens, while the logic still knows where it came from by inspecting the detail object. Decoupling using custom events makes testing easier.

window.addEventListener('update-request', updateStuff);
const updateStuff = async (event) => {
  await doStuff;
};

So far, so good. In the next installment I'll tie it together with a custom component.


Posted by on 13 November 2025 | Comments (0) | categories: Javascript WebComponents WebDevelopment

A flexible filter for collections or maps


Building a proxy for http requests I came across an interesting generic problem: filter or mutate a map but only for the occurence of some given set of keys.

That's a lot of if - else - switch

The going approach is to have a specialized method with a switch:

  Map<String, String> transformMap(Map<String, String> input, String joker) {
    Map<String, String> result = new HashMap<>();

    input.entrySet().forEach(entry -> {
      String key = entry.getKey();
      String value = entry.getValue();
      switch (key) {
        case "a":
          result.put(key, "alpha");
          break;
        case "b":
          result.put(key, "beta");
          break;
        case "j":
          result.put(key, joker + "!");
        default:
          result.put(key, value);
      }
    });

    return result;
  }

This gets big and hard to maintain fast, so I was thinking of a more neutral approach entertaining Function and Optional, hear me out.


Read more

Posted by on 04 October 2025 | Comments (0) | categories: Java

Arguing with Claude about StableCoins


Winding down after a busy week, I decided to have som fun with Claude, so I asked

Explain to an A-Level student what stable coins are

Explain how they are created, distributed and backed. List the business model for coin issuers and traders. Discuss their advantages and risks compared to other cryptocurrencies as well as fiat currencies.


Read more

Posted by on 26 September 2025 | Comments (1) | categories: After hours AI

Authentication with PKCE and vanilla JavaScript


Finally you got rid of user management in your application since your organisation has standardized on an IdP. There are plenty to choose from. I usually develop using a Keycloak IdP before I test it with the target IdP (and yes: Azure Entrada tries to be different).

So it's time to adjust your SPA to use the IdP. The admins tell you, you need to use PKCE, part of the OIDC specification

Where is the fun in ready made?

A quick search on npmjs shows, the topic is popular and AWS takes the crown. But for deeper understanding, let's roll our own.

Prerequisites

There are just four items you need. The first three are provided by your IdP admins, the forth one you have to provide to them.

  • The URL of your IdP, the full path where .well-known can be found. That's usually the root, but does differ for Entrada or Keycloak
  • The issuer. That typically is the URL, except for Entrada
  • The clientId. A String, usually opaque
  • The callback urls. Pick those wisely. Typically you want three: http://localhost:3000/myApp, https://localhost:8443/myApp and https://final.place.com/myApp The first two enable you to test your application locally with both http and https

Read more

Posted by on 01 September 2025 | Comments (0) | categories: JavaScript WebDevelopment

Installing a macOS developer workstation


It is sitting on my desk, a shiny M4 MacBook. It wants to be configured. I can take the easy route and use the Migration Assistant. But that would carry forward all the cruft the various incarnations of the Migration Assistant have accumulated over the decade. So I went the hard way.

Manual with a dash of AppStore

First Stop: update macOS. In my case Sequoia 15.1 -> 15.6.1

Installation falls into 3 categories

  • command line tooling
  • settings & data
  • GUI applications

Followed by the reconfiguration of license keys


Read more

Posted by on 29 August 2025 | Comments (0) | categories: Development macOS

CouchDB, JWKS and PEM public keys


Depending on how deep you authenticate, you might be tasked maintaining a user base in _users (and welcome to "I forgot my password" hell). The standing recommendation is to implement a single source of identity using a directory as Identity Provider (IdP). My favorite NoSQL database can be configured to trust JWT signed by known IdPs, so let's do that.

Some assembly required

CouchDB can be configured in three ways: Edit the respective ini file, use the Fauxton UI or use the REST API. I like the later since I'm comfortable with curl and Bruno (not a fan of Postman anymore). The steps are:

  • configure a client on your identity provider
  • enable JWT authentication
  • specify what claims are mandatory
  • specify how to map roles
  • add trustedd public keys
  • restart your node

Read more

Posted by on 30 July 2025 | Comments (0) | categories: CouchDB JWT

Report your CSP (violations)


I'm a big fan of a strict Content Security Policy (CSP). It can be a pain to setup (but there is help, here, here, here and here) and evaluate.

Let's report it

You won't know if a policy was tried to be violated unless the attempt is reported back to your application. For that purpose we use the CSP directives report-to and the older, deprecated report-uri. Until Firefox catches up, use both. When a browser supports report-to, report-uri gets ignored.

Reporting isn't only useful in production, but already during development and especially during retrofitting. There you can swap the Content-Security-Policy header for Content-Security-Policy-Report-Only. It will allow all content to load, but report back all violations.

You then run your E2E Tests (You have those, haven't you?) and get a free overview what loads from where. Adjust the CSP, rinse and repeat.

Where to report to?

There are numerous SaaS providers with fancy dashboards, that offer ready made solutions. When you are pressed for time, that might be your best option. I haven't evaluated them, so I can't recommend or endorse them.


Read more

Posted by on 07 July 2025 | Comments (0) | categories: Java JavaScript Rust WebDevelopment

HTML's template element in single page applications


"We need to use [insert-framework-of-the-day]!" is the typical answer when asking for a light web single page application (SPA).

It doesn't need to be that way, Paul and myself shared in a recent webinar.

Serving the long tail

Long Tail Apps tend to be outside of IT control, since they bypass the (usually heavy) standup of an IT development project.

That standup could be way lighter, when your application just consists of one html file, one css file, one js file, one manifest and (optionally) one or more image files as well as a definded point of deployment.

The typical objection goes: "But it is never one HTML file, I need a login, a list and a form in read and edit mode"

template to the rescue

The <template> element is part of the WebComponents specification and it is useful in simple SPA applications.


Read more

Posted by on 23 June 2025 | Comments (0) | categories: WebComponents WebDevelopment

Fun with AI system prompts


AI Chatbots are a popular topic. As part of a session at Engage 2025 I was looking for an easy to grasp example to understand the difference of user prompt and system prompt, the later typically invisible to the user. My goal was to make it abundantly clear how important the system prompt is.

I settled sending the same user prompt with vastly different system prompts. Here is what I got.

Romeo at the balcony

Mercutio’s mocking my love and he’s never been in love himself.

Wait. What’s that light coming from the window over there? It’s like the east, with Juliet as the morning sun! Rise, Juliet, beautiful sun, and kill the jealous moon who’s already fading and sad because you are far more beautiful than she is. Don’t swear off men like the virgin moon goddess Diana—the moon envies you anyway. Her virginal appearance is weak and pale and only fools want to emulate it. Get rid of it.

It’s my lady! Oh, it’s my love. Oh, if only she knew I love her. She’s talking but I can’t hear anything. What does it matter?

Her expression means something and I can answer that. No, I’m being too forward. She’s not talking to me. Oh, if two of the most beautiful stars had to leave heaven on important business, they’d ask her eyes to do the twinkling for them while they were gone! What if her eyes took their places in the sky and those stars became her eyes? Her beautiful face would outshine those stars in her head like daylight outshines lamps, while her eyes in the sky would be so bright at nighttime that birds would be convinced it was day. Look at how she leans her cheek on her hand. I wish I were a glove on her hand so I could touch her cheek!


Read more

Posted by on 07 May 2025 | Comments (0) | categories: AI