Container
manages dependencies and performs dependency injection. Dependency injection is a fancy phrase for “registering” and “resolving” services with a certain interface. Doing so makes your services easier to mock in tests or swap out for various implementations.
Out of the box, your Alchemy app is configured with a variety of essential services. If you need to add more, you can do so directly through your application’s var container: Container
. For larger groups of services and associated logic, you can write a custom Plugin.
register
function of a container which takes a factory closure that will be used to create a service of that type when it’s resolved. The closure has a single Container
to resolve other services that may be dependencies.
as
.
Container.main
) you can call all of these functions statically.
Hashable
, like a String
or Int
.
.singleton()
after registering.
resolve()
function. This will return an optional instance of the service, returning nil
if the service isn’t registered.
resolveOrThrow
which throws an error if the service hasn’t been registered.
require
which will just stop program execution if the service isn’t registered.
id:
parameter to any of the above functions.
@Inject
you can conform the enclosing type to Containerized
. This will cause @Inject
to resolve from the container on the enclosing type.
Containerized
requires that the enclosing type is a class.DB
resolves your app’s default Database
.
Container.resolve(Database.self)
. Using aliases you can easily use dependency injection without cluttering up your code with a bunch of Container.resolve(...)
calls.
You can access an identified service this way as well.
Service
protocolService
protocol. This gives them an associated identifier type, Service.Identifier
. You can use this type to create typesafe identifiers for accessing various service instances through aliases.
Alias | Service Type | Description |
---|---|---|
DB | Database | Your app’s default database. |
Http | Client | A client for making HTTP requests. See HTTP Client. |
Lifecycle | ServiceLifecycle | The app’s lifecycle. See App Lifecycle. |
Env | Environment | The app environment. See Environment |
Log | Logger | The default app logger. See Logging. |
Schedule | Scheduler | Cron like scheduler for recurring tasks. See Task Scheduling. |
Storage | Filesystem | Filesystem for storing and loading files. See File Storage. |
Stash | Cache | Key value cache. See Cache. |
Q | Queue | Queue for running background jobs. See Queues. |
Redis | RedisClient | A Redis client. See Redis. |
Events | EventBus | A pub/sub system of events throughout the application. See Events. |
Hash | Hasher | Hashes and verifies passwords. See Hashing. |
Crypt | Encrypter | Encrypts and decrypts arbitrary data. See Encryption. |
Loop | EventLoop | The current event loop. See SwiftNIO services. |
LoopGroup | EventLoopGroup | The app’s event loop group. See SwiftNIO services. |
Thread | NIOThreadPool | The app’s main thread pool. See SwiftNIO services. |
Application
type essentially just loads and boots a variety of plugins. You can register additional plugins in your application’s configuration.
A plugin has three optional functions - registerServices(...)
, boot(...)
, and shutdownServices(...)
.
registerServices
boot
registerServices
has been called on all plugins. Therefore it is safe to access all services. Here a plugin should perform any startup logic for its registered services. It can also interact with any services from other plugins it might depend on to do things like add routes to the application or add migrations to the default database.
shutdownServices
ServiceLifecycle
from the application container or with the Lifecycle
alias.
boot()
function is called. If you need to register a service to the lifecycle’s startup, you’ll need to do so in that function.EventLoopGroup
is accessible via the container or the LoopGroup
alias.
EventLoop
is accessible via the container or the Loop
alias.
EventLoop
the next available EventLoop
from the main EventLoopGroup
will be return.NIOThreadPool
is accessible via the container or the Thread
alias.
run(...)
to NIOThreadPool
that provides an async interface for running expensive work on a background thread and then returning the result of the work to the current EventLoop
.
Container
.