PlatformEngr® Backstage plugins course

Cheat notes · Module 04 · The backend plugin

An extension point and a module

A five-minute review for when you have done this module and want it back in your head. Open the full module for the steps and the lab, or the full text to print.

The idea

An extension point turns "please add our check" into "write a module". The plugin offers it during register; modules use it in their init, which always runs before the plugin's init.

Remember

  • createExtensionPoint<T>({ id }): defined in the -node package (readiness-node), so modules depend on a small, stable contract, never on the plugin's internals.
  • Offering it: in the plugin's register, env.registerExtensionPoint(ref, { addCheck(...checks) { list.push(...checks) } }), before registerInit.
  • createBackendModule({ pluginId, moduleId }): extends one plugin and may only use that plugin's extension points.
  • Start order: all modules of a plugin finish init before the plugin's init runs, so every check is in the list in time.
  • Ownership: the module is team-checkout's code in its own package and folder; they review it.
  • Generate it: yarn new --select backend-plugin-module --option pluginId=readiness --option moduleId=api.

Pitfalls

  • A typo in pluginId (readyness): the backend starts, nothing is red, and the check silently disappears. The module's own test starts the real plugin with the module and expects the check in /checks.
  • Importing the extension point from readiness-backend: modules then break whenever the plugin changes inside.

Commands

yarn new --select plugin-node-library --option pluginId=readinessThe -node package for the extension point
yarn new --select backend-plugin-module --option pluginId=readiness --option moduleId=api --option pluginPackage=@internal/backstage-plugin-readiness-backendA module for the plugin, wired into the backend
curl -s -H "Authorization: Bearer $PORTAL_API_TOKEN" localhost:7007/api/readiness/checks | jq -r '.items[].id'Is the module's check listed?

A module using the extension point

export const readinessModuleApi = createBackendModule({
  pluginId: 'readiness',          // must match exactly
  moduleId: 'api',
  register(reg) {
    reg.registerInit({
      deps: { checks: readinessChecksExtensionPoint },
      async init({ checks }) {
        checks.addCheck(providesApiCheck);
      },
    });
  },
});

Test yourself

Answer in your head first, then open the answer.

Why is the extension point in readiness-node and not readiness-backend?

So modules depend on a small package and never on the plugin's internals.

When does the module's init run?

Before the plugin's init, so its check is in the list in time.

Who reviews a change to provides-api?

team-checkout, who own the module.

Where module 04 leaves you: Six checks, one owned by team-checkout in its own package. checkout scores 83. Merged.