Extending Hummingbird

The HBApplication, HBRequest and HBResponse classes all contain an HBExtensions object that allows you to extend these classes with your own objects. The extension objects are stored in a dictionary with a KeyPath as their key.

extension HBApplication {
    public var myExt: String? {
        get { self.extensions.get(\.myExt) }
        set { self.extensions.set(\.myExt, value: newValue) }
    }
}

The code above adds the member variable myExt to the HBApplication class. I use the KeyPath to the variable as the key. While it would be possible to use another KeyPath as the key it doesn’t really make sense.

In the example above the member variable is an optional, to ensure you will always get a valid value when referencing HBApplication.myExt. You can set the variable to be non-optional but you will have to ensure you set the variable before ever accessing it, otherwise your application will crash.

For extensions to HBApplication you also get the added bonus of being able to add a shutdown call for when the application is shutdown. In the example below we have extended HBApplication to include a AWSClient from the package Soto. It is required you shutdown the client before it is deleted. The extension shutdown can be used to do this for you.

extension HBApplication {
    public struct AWS {
        public var client: AWSClient {
            get { application.extensions.get(\.aws.client) }
            nonmutating set {
                application.extensions.set(\.aws.client, value: newValue) { client in
                    // shutdown AWSClient
                    try client.syncShutdown()
                }
            }
        }
        let application: HBApplication
    }

    public var aws: AWS { return .init(application: self) }
}

Note, I have placed everything inside a containing struct AWS, so the KeyPath \.aws.client needs to include the name of containing member variable in it as well.

Extending EventLoop

In certain situations it can be useful to hold data on a per EventLoop basis. You can do this by extending the class HBApplication.EventLoopStorage. The class can be extended in the same way as above. You then access the storage either via HBApplication.eventLoopStorage(for:) or HBRequest.eventLoopStorage.

extension HBApplication.EventLoopStorage {
    public var index: Int? {
        get { self.extensions.get(\.index) }
        set { self.extensions.set(\.index, value: newValue) }
    }
}
func getIndex(_ request: HBRequest) {
    let index = request.eventLoopStorage.index
    ...
}

This is used by the DateCache in HummingbirdFoundation and also by the Redis interface that can be found here.