Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Contexts

Contexts are data available through a whole track. Unlike parameters, they inherently exists and are accessible by all treatments requiring them, as long as the source of the track they are in provide it.

The calling treatments don’t have to explicitly pass any context to their inner called treatments. Contexts have special naming convention, starting with @.

Context providing and requirement

Sources provide contexts, and treatments connected after that source can require the context to access it.

Requiring a context means the treatment can only be used in a track coming from a source providing such context.

The following minimal example shows the pattern: a source treatment provides @ConnectionId, and a downstream treatment requires it without being explicitly passed anything:

// A context carrying a connection identifier for the current track.
// In practice, contexts like this are provided by library models (HTTP, files, etc.).

treatment logRequest()
  require @ConnectionId
  input  data:   Stream<byte>
  output result: Stream<byte>
{
    // @ConnectionId[id] accesses the "id" field of the context.
    // Its value comes from the track source, not from a parameter.
    process(connection_id = @ConnectionId[id])

    Self.data -> process.data,result -> Self.result
}

logRequest can only be used inside a track whose source provides @ConnectionId. Treatments further down the chain do not need to pass it explicitly: it is available to any treatment in the track that declares require @ConnectionId.

Below is a real-world example using the HTTP server, where @HttpRequest is provided by the connection source treatment:

use http/server::HttpServer
use http/server::connection
use http/method::|get as |methodGet
use http/server::@HttpRequest
use http/status::|ok
use http/status::HttpStatus
use std/data/string_map::|get
use std/data/string_map::|map
use std/data/string_map::StringMap
use std/flow::trigger
use std/flow::emit

treatment myApp[http_server: HttpServer]() {
    connection[http_server=http_server](method=|methodGet(), route="/user/:user")
    actionGetUser()

    connection.data -> actionGetUser.data,result -> connection.data
    
    trigger<byte>()
    emitHeaders: emit<StringMap>(value=|map([]))
    emitStatus: emit<HttpStatus>(value=|ok())
    
    actionGetUser.result -> trigger.stream,start -> emitHeaders.trigger,emit -> connection.headers
                            trigger.start --------> emitStatus.trigger,emit --> connection.status
}

treatment actionGetUser()
  require @HttpRequest
  input  data:   Stream<byte>
  output result: Stream<byte>
{
    getUser(user_id = |get(@HttpRequest[parameters], "user"))

    Self.data -> getUser.data,result -> Self.result
}

treatment getUser(user_id: Option<string>)
  input  data  : Stream<byte>
  output result: Stream<byte>
{
    // Do some stuff…
}

Reference for HttpServer, connection, |get (http method), @HttpRequest,|get (map access)

myApp graph
myApp

actionGetUser graph
actionGetUser

As contexts comes at track creation, they are inherently variable data.