diff --git a/docs/api/backend.md b/docs/api/backend.md index fd3da4fbd8..5f04d38214 100644 --- a/docs/api/backend.md +++ b/docs/api/backend.md @@ -8,22 +8,32 @@ description: About Backend **DISCLAMER: The new backend system is under active development and is not considered stable** +This is an example of how you create, start and add existing plugins to your backend. + +```ts +import { createBackend } from '@backstage/backend-defaults'; + +const backend = createBackend(); + +// backend.add(catalogPlugin()); +await backend.start(); +``` + ### Overview -The default backend provides several services out of the box which are available to all plugins but there might cases where you want to provide a completely new service in your installation. +The default backend provides several _services_ out of the box which includes access to config, logging, scheduling and more. +Service are declared using their _serviceRef_ in the `deps` section of plugin or module requiring them and are then available in the `init` method of the plugin or module. ### Service Refs -A serviceRef is a named reference to an interface which are later used to resolve the actual service implementation. Conceptually this is very similar to `ApiRef`s in the frontend. +A serviceRef is a named reference to an interface which are later used to resolve the concrete service implementation. Conceptually this is very similar to `ApiRef`s in the frontend. Services is what provides common utilities that previously resided in the `PluginEnvironment` such as Config, Logging and Database. On startup the backend will make sure that the services are initialized before being passed to the plugin/module that depend on them. -ServiceRefs does contain a scope which is used to determine if the serviceFactory creating the service will create a new instance for each plugin/module or if it will be shared. `plugin` scoped services will be created once per plugin and `root` scoped services will be created once per backend instance. +ServiceRefs contain a scope which is used to determine if the serviceFactory creating the service will create a new instance scoped per plugin/module or if it will be shared. `plugin` scoped services will be created once per plugin/module and `root` scoped services will be created once per backend instance. #### Defining a ServiceRef -In its simplest form the serviceRef can be defined like this referencing the type of the actual implementation. - ```ts import { createServiceFactory, @@ -65,7 +75,7 @@ export const exampleServiceRef = createServiceRef({ ### Overriding services -In this example replace the default log implementation with a custom one. +In this example replace the default log implementation with a custom logger. ```ts import { @@ -92,15 +102,39 @@ const backend = createBackend({ }) ``` -#### API Overview -`createBackend` -`createBackendPlugin` -`createBackendModule` -`createServiceRef` -`createExtensionPoint` -### Writing Plugins +## Writing Plugins -### Writing modules +```ts +import { configServiceRef, createBackendPlugin } from '@backstage/backend-plugin-api'; + +// export type ExamplePluginOptions = { exampleOption: boolean }; +export const examplePlugin = createBackendPlugin({ + // unique id for the plugin + id: 'example', + // It's possible to provide options to the plugin + // register(env, options: ExamplePluginOptions) { + register(env) { + env.registerInit({ + deps: { + logger: loggerServiceRef, + }, + // logger is provided by the backend based on the dependency on loggerServiceRef above. + async init({ logger }) { + logger.info('Hello from example plugin'); + }, + }); + }, +}); +``` + +The plugin can then be installed to the backend using + +```ts +backend.add(examplePlugin()); +// Options can be passed to the plugin +// backend.add(examplePlugin({ exampleOption: true})); +``` +## Writing Modules Some facts about modules @@ -110,13 +144,35 @@ Some facts about modules A module depend on the extensionPoint exported by the plugins library package(eg `catalog-node`, `scaffolder-backend`) and does not directly declare a dependency on the plugin package itself. +Here's an example on how to create a module that adds a new processor using the `catalogProcessingExtensionPoint` +```ts +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node'; +import { MyCustomProcessor } from './processor'; -### Overwriting services - +export const exampleCustomProcessorCatalogModule = createBackendModule({ + moduleId: 'exampleCustomProcessor', + pluginId: 'catalog', + register(env) { + env.registerInit({ + deps: { + catalog: catalogProcessingExtensionPoint, + }, + async init({ catalog }) { + catalog.addProcessor(new MyCustomProcessor()); + }, + }); + }, +}); +``` ### Extension Points +Modules depend on extension points just as a regular dependency but specifying it in the `deps` section. + +#### Defining an Extension Point + ```ts import { createExtensionPoint } from '@backstage/backend-plugin-api'; @@ -130,4 +186,38 @@ export const ScaffolderActionsExtensionPoint = }); ``` +#### Registering an Extension Point + +Extension points are registered by a plugin and extended by modules. + + ### Testing + +Utilities for testing backend plugins and modules are available in `@backstage/backend-test-utils`. + +```ts +import { startTestBackend } from '@backstage/backend-test-utils'; + +describe('Example', () => { + it('should do something', async () => { + await startTestBackend({ + // mock services can be provided to the backend + services: [someServiceFactory], + // plugins and modules for testing + features: [testModule()], + }); + // assertions + }); +}); +``` + + +## Package structure + +The package relationship between plugins, modules and extension are illustrated in the following diagram. + +Taken with an artificial foobar backend plugin. + +- `plugin-foobar-backend` houses the plugin and registers the extension points into the backend system. +- `plugin-foobar-common` houses the shared types including the Extension Point registered by the backend. +- `plugin-foobar-XYZ-module` houses the modules that extend the foobar backend with extension points imported from `plugin-foobar-common`