ServiceContext

A ServiceContext is a heterogeneous storage type with value semantics for keyed values in a type-safe fashion.

ServiceContext.swift:67
struct ServiceContext

Its values are uniquely identified via ServiceContextKeys (by type identity). These keys also dictate the type of value allowed for a specific key-value pair through their associated type Value.

Defining keys and accessing values

ServiceContext keys are defined as types, most commonly case-less enums (as no actual instances are required) which conform to the ServiceContextKey protocol:

private enum TestIDKey: ServiceContextKey {
  typealias Value = String
}

While defining a key, one should also immediately declare an extension on ServiceContext to allow convenient and discoverable ways to interact with the context item. The extension should take the form of:

extension ServiceContext {
  var testID: String? {
    get {
      self[TestIDKey.self]
    } set {
      self[TestIDKey.self] = newValue
    }
  }
}

For consistency, it is recommended to name key types with the ...Key suffix (e.g. SomethingKey) and the property used to access a value identifier by such key the prefix of the key (e.g. something). Please also observe the usual Swift naming conventions, e.g. prefer ID to Id etc.

Usage

Using a context container is fairly straight forward, as it boils down to using the prepared computed properties:

var context = ServiceContext.topLevel
// set a new value
context.testID = "abc"
// retrieve a stored value
let testID = context.testID ?? "default"
// remove a stored value
context.testIDKey = nil

Note that normally a context should not be “created” ad-hoc by user code, but rather it should be passed to it from a runtime. A ServiceContext may already be available to you through ServiceContext.$current when using structured concurrency. Otherwise, for example when working in an HTTP server framework, it is most likely that the context is already passed directly or indirectly (e.g. in a FrameworkContext).

Accessing all values

The only way to access “all” values in a context is by using the forEach function. ServiceContext does not expose more functions on purpose to prevent abuse and treating it as too much of an arbitrary value smuggling container, but only make it convenient for tracing and instrumentation systems which need to access either specific or all items carried inside a context.