Service Reference

Services act as a repository of accessible behavior and data, and can be used for a variety of purposes, from implementing commands and operations, to managing shared data, to interfacing with the REST API of an external service.

Service Registration

All services need to be registered with Geocortex Web. Services can optionally use the itemType property to bind to an item in the app config.

export default function(registry: LibraryRegistry) {
...
registry.registerService({
id: "custom-service",
getService: (config) => new CustomService(config),
// Use this setting if you want your service to load an
// item from the app config.
itemType: "custom-service-model",
// Use this setting if you want your service to load on
// application startup. Defaults to `false`.
loadOnStartup: true,
})
...
}

Service Lifecycle

On application load, all services that are configured to automatically load on startup are created and initialized in parallel, along with core services like the message bus.

All other services are created and initialized (i.e. the _onInitialize method is called) when they are first invoked. This can happen in multiple ways.

  • If a command or operation implemented by the service is executed, then the service will be created and initialized to run that command.
  • If a different component or service injects the service, then the service will be created and initialized to fulfill that dependency.

Services are destroyed (i.e. the _onDestroy method is invoked) when the application is destroyed.

Service Anatomy

All services have access to initialization and cleanup methods, as well as the messages property that allows for the registration and execution of commands and operations.

Initialization and Cleanup

Sometimes, a service is required to perform initialization and cleanup actions, for example, to initialize dynamic data and cleanup dangling references. The ServiceBase class has two methods to achieve this:

  • _onInitialize(), which can be overridden with additional initialization logic,
  • and _onDestroy(), which can be overridden to facilitate cleanup.

The following service uses these methods to subscribe to an event and cleanup the event handler afterwards.

important

Always call super._onInitialize() before any custom initialization logic.

import { ServiceBase } from "@vertigis/web/services";
import { MapEvent } from "@vertigis/viewer-spec/messaging/registry/map";
export default class CustomService extends ServiceBase {
handles: IHandle[] = [];
protected async _onInitialize(): Promise<void> {
await super._onInitialize();
this.handles.push(
this.messages.events.map.initialized.subscribe((e: MapEvent) => {
console.log(
"Map Initialized, do your map dependent model setup here."
);
})
);
return;
}
protected async _onDestroy(): Promise<void> {
await super._onDestroy();
this.handles.forEach((h) => h.remove());
}
}

Message Bus

All services have access to the messages property on the class instance, which gives access to all commands, operations, and events in the application.

Models and Configuration

Like components, services can be configured through the app config. A service can participate in the config by extending the ConfigurableServiceBase class. For more information on the relationship between services and configuration, check out this article. The following example demonstrates a service with one configurable property, name.

note

The service is linked to the config through the itemType and id properties.

export interface CustomServiceProperties extends ServiceModelProperties {
name: string;
}
@serializable
export default class CustomServiceWithConfig extends ConfigurableServiceBase<
CustomServiceProperties
> {
id: "my-unique-id";
name: string;
async sayHello(): Promise<string> {
return `Hello, ${this.name}`;
}
protected _getSerializableProperties(): PropertyDefs<
CustomServiceProperties
> {
return {
...super._getSerializableProperties(),
name: {
serializeModes: ["initial"],
default: "Ian",
},
};
}
}

Next Steps

Learn how to use Commands and Operations with Services

Learn how to run and implement commands and operations with custom services

Learn about Service Interactions

Learn about how services can directly interact through dependency injection

Build a Custom Command with a Custom Service

Follow a step by step guide to building a custom command with a custom service

Build a Service that Manages Dynamic Data

Built a service that manages a dynamic data source and exposes it to components