Service Providers
At its core, service providers are nothing more than just classes that allow you to register and boot your services in a more controlled way in one central place. They have few lifecycle methods that you can hook into to register and bootstrap your bindings.
Your service provider class is also where you declare Alpas console commands that are meant be to run from the command line.
The core of Alpas framework itself is built with many service providers.
/alert/ Unlike configs, service providers are not automatically registered by the framework. It's up to you to register your service providers in either one or both of
HttpKernel
andConsoleKernel
.
Getting Started
A service provider is just a class that implements dev.alpas.ServiceProvider
interface:
// providers/ExceptionReportingServiceProvider.kt
class ExceptionReportingServiceProvider : ServiceProvider {
override fun register(app: Application) {
// Register a service.
// Not all service providers are registered yet.
}
override fun boot(app: Application) {
// Boot a service.
// All service providers are registered.
}
override fun commands(app: Application): List<Command> {
// Return a list of Alpas console commands.
// Called right after the Register method.
// Not all the service providers are registered yet.
}
}
/tip/ All service provider methods receives the global app instance, which is an IoC Container. Use this app instance to register your bindings or to resolve dependencies.
register()
The register
method is where you should register your bindings with the IoC Container.
Since not all the service providers are necessarily registered by the time this register method is called,
you shouldn't try to use any other bindings inside this method.
boot()
The boot
method is called when all the providers have been registered (but not necessarily booted). You should be
able to use other bindings provided by other service providers inside this method.
commands()
Your service providers may have some Alpas console commands. The commands
method is the perfect place
to return a list of all those commands. This method is called right after the register
method so
not all the service providers are registered yet.
Registering Service Provider
Once you have created a service provider, you must register it by appending it to the list of service providers
returned by serviceProviders()
method in either one or both of HttpKernel
or ConsoleKernel
classes.
Whether to register your service provider in one or both the kernels depends on what mode you want your service
provider to be available in. For an example, by default the ViewServiceProvider
class is added to only
HttpKernel
and not to ConsoleKernel
as it doesn't make sense to have any view related
services available in console mode.
Let's see a complete example of writing a service provider. Say we want to have an error reporter service that we
can call whenever we want to log an exception. Also, let's assume that it provides a console command error:send
that
sends any cached errors immediately.
// providers/ErrorReportingServiceProvider.kt
class ErrorReportingServiceProvider : ServiceProvider {
override fun register(app: Application) {
app.bind(RemoteErrorReporter())
}
override fun boot(app: Application) {
app.make<RemoteErrorReporter>().prepare(app.env)
}
override fun commands(app: Application): List<Command> {
return listOf(SendAndClearErrors())
}
}
// RemoteErrorReporter.kt
class RemoteErrorReporter {
fun report(e: Exception) {
// sends the error somehow
}
fun prepare(env: Environment) {
// do something
}
}
// console/commands/SendAndClearErrorsCommand.kt
class SendAndClearErrorsCommand : Command(name = "error:send")
Register the service provider
// HttpKernel.kt
class HttpKernel : HttpKernel() {
override fun serviceProviders(app: Application): Iterable<KClass<out ServiceProvider>> {
return listOf(
// ...,
// ...,
// ...,
ErrorReportingServiceProvider::class,
// ...,
// ...
)
}
}
Use the registered service
// controllers/AdminController.kt
class AdminController : Controller() {
fun greet(call: HttpCall) {
if (!call.isAuthenticated) {
val ex = AuthenticationException("Suspicious activity 😱")
call.make<RemoteErrorReporter>().report(ex)
call.abort()
} else {
call.reply("Hello, Admin!")
}
}
}