View Attaching
Introduction
When the browser sends a request to the server, the app with the matching URI sends back a response with the view. Starcounter has a unique feature of attaching views from other apps to the main view in the same response using a system based on tokens and contexts.
For example, if a user wants to see a profile of a person, the browser makes a request to the People app: GET http://localhost:8080/people/person/4782
. The response that is sent to the browser will include not only the view from the People app but also views from other apps that are attached to it.
On a high level, these are the specific steps involved with sending the response:
The browser makes a request for a resource, such as:
GET http://localhost:8080/people/person/4782
.The server receives the request and routes it to the corresponding handler in an app (People).
The handler is mapped to a token that describes the sort of resource it deals with, in this case, it's the person table in the database (
simplified.ring2.person
).The server requests responses from all the other handlers registered in the code host that are mapped to the same token.
For the responses from other apps that are views, the server attaches the views to the view from the initial handler (which is called the main view) during the serialization process.
The server sends the response, which now contains views from multiple apps, back to the client.
By using tokens, the apps don't need to know anything about other apps in the code host - they don't even need to know if there are other apps - they only have to communicate what concept the handlers deal with. Thus, apps should be built to not depend on, or expect, attaching.
The process of mapping handlers to tokens and attaching responses is handled by the Blender
class in the Starcounter
namespace.
Attaching works well with view composing to make different apps looks like one.
Attaching was previously called "server-side blending"
Tokens
Attaching uses tokens. These tokens are either strings or classes. Handlers with the same token are called on internal Self.GET
calls or external URI that matches one of the handlers. Once the handler with a token is called, it will not trigger further calls mapped to that handler directly, only when a new Self
call is made.
The first parameter is either a handler URI or a specific URI. If the token is a string, it's defined as the second parameter. If it's one or more classes, they are defined in the template or as a Type
array parameter.
An arbitrary number of classes are allowed as tokens (up to 3 in template, more in array of class Type
). Here are the MapUri
signature examples (same exist for removing token mapping from a handler):
Handlers can be mapped to empty tokens:
Handlers with empty tokens are called with other handlers with the same empty token.
Contexts
Token matching can be made more fine-grained by using contexts. They are composed of a list of strings that acts as a bit map when matched with other contexts. No context (null
value) means match any context. Otherwise, two handlers are matched if source context contains same elements as destination context. Examples:
Source context
{ "Readable", "View" }
is NOT matched with{ "Writable", "View" }
.Source context
null
is matched with{ "Readable", "View" }
and{ "Writable", "View" }
and any other context.Source context
{ "View", "Writable" }
is matched with{ "Writable", "View" }
and vice versa.
Consider contexts as an additional matching rule for handlers with the same token.
Attaching Specific URIs
Specific URI is the handler URI with parameters supplied. For example, for the handler /people/{?}
the specific URIs will be /people/john
, /people/bob
, etc. When calling Blender.MapUri
for a specific URI, you should pass a mixed URI which indicates what handler it belongs to. For the previous examples, the mixed URI will be /people/{john}
and /people/{bob}
, so the parameter in specific URI is wrapped into curly brackets. Blender
class has helper methods to construct such mixed URIs: Blender.GetMixedUriFromHandlerAndParameters
, Blender.TryGetMixedUriFromSpecific
. The last method tries to find corresponding handler for the given specific URI, which might not be determined correctly (for example, in case when the corresponding handler is not yet registered). Mixed URIs in MapUri
calls are needed so the underlying handler for a specific URI can be identified. Other Blender
methods like UnmapUri
, IsMapped
, etc. can still use specific URIs and not mixed.
Dynamic Addition and Removal
Handlers that are registered and mapped to a token can dynamically have the mapping removed with UnmapUri
:
IsMapped
is used to check if a handler is mapped to a token:
To get a dictionary of all handlers and their respective tokens, use ListAllByTokens
or ListAllByUris
:
The dictionary returned by ListAllByTokens
has the token as the key. The entries in the dictionary are sorted alphabetically based on the token. The same applies for ListByAllUris
but for URIs.
To get the list of blending candidates that are going to run for a given URI handler:
To list registered blending rules for a given URI:
and the same but for a given token:
As you might noticed, a special blending information structure is used here: BlendingInfo
.
It contains the following methods/properties:
Parameters in Handlers
Handlers are allowed to have an arbitrary number of parameters. When there is at least one parameter, the conversion functions are used. First converter translates handler arguments to token arguments, while the second converter does the opposite. Both converters are taking and returning an array of strings:
In the example above, converter passes handler parameters to token parameters, as is. There are signatures of Blender.MapUri
with no converters, which means that parameters are simply passed through, like above.
Often it's needed to trigger attachment on a specific URI. To achieve this, first converter should return non-null string array on certain parameters.
Call Direction
You can specify the direction of which handlers should be called. This is needed to trigger attaching in a certain direction: from handler or to handler. The direction is determined by the value that corresponding converter is returning: null
converter or null
string array returned in converter blocks the direction of the call. In case of zero parameters, there is a special Blender.MapUri
override with corresponding boolean parameters to determine the allowed call directions.
In the first example above, handler "/twoparams1/{?}/{?}" should not trigger calls on the myToken
token, but it can be called when attaching is triggered by other handlers on the same token.
In the second example above, handler "/noparam1" can trigger other handlers on the same token, but can't be triggered by them.
Same Handler - Different Tokens
Handlers can be mapped to multiple tokens:
Here, the handler /app1/{?}
is mapped to the token1
and token2
.
When an app requests Self.GET("/app1/xyz")
, both handlers mapped to token1
and token2
will be triggered.
Separate blending rules in JSON
You can describe blending rules in JSON, separate from the application code. If the file blend.json
is in the same directory as the starting application assembly - the file is parsed and the extracted blending rules are applied right after the Main
method. The same happens when the application restarts. With this mechanism, blending rules can be changed for shipped application, where you only have the binaries. Here is an example of the content of a blend.json
file:
Each element of the array contains the following fields:
In short, the meaning of the above fields is the same as in Blender.MapUri
functions variations.
Last updated