New Services API
March 25, 2015 jlord
Many packages don’t just work in isolation, they depend on other packages. For instance, the vim-mode
package depends on the status-bar
package because it uses it to display the current editing mode.
Previously a package like vim-mode
would be forced to wait for all packages to load and then query the DOM for the status-bar
in order to interact with it. Not only was this cumbersome, but it also created the possibility for breakage if the API of the status-bar
ever changed.
Node’s package manager, npm
, solves a similar problem for static dependencies by giving each library its own copy of its dependencies based on a semantic version range. But in this case, we can’t give every package its own copy of the status bar, since there’s only one status bar in the atom workspace.
Providing and Consuming Services
Atom’s solution is the new Services API, which allows packages to provide semantically versioned APIs for other packages to consume. With services, the status-bar
package can provide multiple versions of its API simultaneously, providing a smooth upgrade path for dependent packages when the status-bar
package evolves its API.
Services will also provide flex-points in the package ecosystem by enabling any package to provide the same service. For example, if someone wanted to implement a status-bar-plus
package with a new and improved status bar, they could still provide the original status-bar
’s services in order to be compatible with packages such as vim-mode
. This ensures that authors will enjoy a level playing field when competing against incumbent packages by preventing calcification of the dependency graph.
Packages define what they are providing and consuming in their package.json
. The status-bar
package’s package.json
contains its provided services API with two versioned methods:
"providedServices": {
"status-bar": {
"description": "A container for indicators at the bottom of the workspace",
"versions": {
"1.0.0": "provideStatusBar",
"0.58.0": "legacyProvideStatusBar"
}
}
}
This gives other packages access to the status-bar
method provideSatusBar
when they consume the ‘status-bar’ service. The vim-mode
package does so by declaring in its package.json
:
"consumedServices": {
"status-bar": {
"versions": {
"^1.0.0": "consumeStatusBar"
}
}
}
Now when vim-mode
calls consumeStatusBar
it is returned the result of the provideStatusBar
method from status-bar
which it can then use to insert the user’s current state.
consumeStatusBar: (statusBar) ->
@statusBarManager.initialize(statusBar)
@statusBarManager.attach()
@disposables.add new Disposable =>
@statusBarManager.detach()
For more details on the Services API see Interacting with Other Packages via Services in the documentation.