Context configurations are how Mojito enables different configurations to be used based on various runtime factors. Many factors are predefined such as language and device, but you can create custom ones as well. These runtime factors are called contexts in Mojito and are mapped to user-defined configurations. For example, you could set the configuration logLevel to ERROR in the production context and set it to INFO in the development context.
Context configurations make it possible to do the following:
The context is the runtime parameters that are either statically set (base context) on the command line or dynamically set (request context) in the HTTP headers and/or the request query string. The configurations for request contexts override those of the base context.
The base context is statically set with the --context option when you start an application.
The following starts the application with the base context environment:production:
$ mojito start --context "environment:production"
Contexts that are dynamically invoked by HTTP requests are called request contexts. When Mojito receives an HTTP request that specifies a context, the configurations mapped to that context will be dynamically applied. The contexts can be specified in HTTP request as a parameter in the query string or in the HTTP header.
The contexts for languages can be requested using the HTTP header Accept-Language. After starting an application with the context "environment:testing", you can dynamically apply the configurations for the context "environment:testing,lang:fr" by sending the HTTP header "Accept-Language: fr". In the same way, the contexts for devices can be requested using the HTTP header User-Agent. The configurations for the context “device:android” could be requested with the HTTP header "User-Agent: Mozilla/5.0 (Linux; U; Android 2.3; en-us)".
The key and value pairs in the context are dynamically set by the query string.
?key1=value1,key2=value2
For example, if an application is started with the base context "environment:testing" and you want to dynamically apply the context "environment:testing,device:iphone", you could append the following query string to the application URL:
?device=iphone
The following lists the contexts that are defined by Mojito. You can define configurations for these predefined contexts. You can combine multiple contexts to form a compound context as well. For example, if you wanted a context to map to configurations for Android devices in a testing environment, you could use the following compound context: "environment:test,device:android"
You can view the supported BCP 47 language tags and default contexts in the dimensions.json file of Mojito. You can also create custom contexts if the Mojito default contexts don’t meet the needs of your application.
When a request is made to a Mojito application, Mojito has to resolve configurations, defined contexts (dimensions.json), and the base/requested contexts before the correct context configurations can be applied.
The following are the steps taken by Mojito to apply the correct context configurations:
Determines Valid Contexts:
Mojito looks for a local dimensions.json. If one is found, Mojito replaces Mojito’s dimensions.json with it. Mojito then uses dimensions.json to determine which contexts are valid. Contexts defined earlier in dimensions.json override contexts defined later in the file.
Merges Configurations
Mojito merges configurations for all contexts, with the configurations in application.json overriding those in defaults.json. If contexts are found that are not defined in dimensions.json, Mojito will throw an error.
Determines Context
Resolves Context Configurations
Mojito then searches for configurations associated with the determined context. The contexts are found in the setting object in configuration files. Mojito will use the more qualified contexts if present over more general contexts. For example, if the merged base and request context is "environment:prod, device:iphone", then Mojito will use it over either "device:iphone" or "env:prod". If "environment:prod, device:iphone" is not present, Mojito will use the request context over the base context as the resolved context.
Applies Context Configuration
Mojito applies the configurations associated with the resolved context.
Configurations for contexts are defined in the application configuration file application.json. Routing configurations for contexts are defined in the routing configuration file routes.json. Default configurations are defined in the defaults.json file of a mojit. All configurations are merged when an application starts. The configuration values in application.json override those in defaults.json.
The application.json and routes.json files in the application directory and the defaults.json file in a mojit’s directory consist of an array of configuration objects. The configuration object has a settings array that specifies the context. The configuration objects in application.json also have a specs object containing mojit instances, which may also have a config object that has data in the form of key-value pairs. The configuration objects in defaults.json do not have a specs object because they do not define mojits, but do have a config object for storing key-value pairs. The routes.json file specifies routing configuration such as the path, HTTP methods, actions, and routing parameters, but does not contain a specs or a config object.
The settings array specifies the context or the default (“master”) that is then mapped to configurations.
Default configurations are used when no context is given. These configurations are found in the object where the settings array has the string “master” as seen below.
[
{
"settings": [ "master" ],
"specs": {
...
}
},
...
]
The context is specified in the settings array of the configuration object.
[
...
{
"settings": [ "environment:development" ],
"specs": {
...
}
},
...
]
Compound contexts are specified in the settings array as a series of contexts separated by commas as seen below.
[
...
{
"settings": [ "environment:development", "device:android" ],
"specs": {
...
}
},
...
]
[
{
"settings": [ "master" ],
"master_route": {
...
}
},
{
"settings": [ "environment:development"],
"dev_route" : {
...
}
}
]
The specs object contains the mojit instances associated with a context.
[
...
{
"settings": [ "environment:production" ],
"specs": {
"photos": {
"type": "PhotoMojit"
}
}
},
...
]
The config object stores configuration for a mojit that is mapped to the context.
[
...
{
"settings": ["device:iphone"],
"specs": {
"iphone": {
"type": "iPhoneMojit",
"config": {
"viewport_width": 320
}
}
}
},
...
]
The configuration objects in application.json below define default configurations and three context configurations. The last context configuration contains two strings containing key-value pairs and is, thus, called a compound context configuration.
[
{
"settings": [ "master" ],
"specs": {
"mainPage": {
"type": "TestMojit"
"config": {
"env": "This is the default environment."
}
}
}
},
{
"settings": [ "environment:development" ],
"specs": {
"mainPage": {
"type": "TestMojit",
"config": {
"env": "I am in the development environment."
}
}
}
},
{
"settings": [ "environment:production" ],
"specs": {
"mainPage": {
"type": "TestMojit",
"config": {
"env": "I am in the production environment."
}
}
}
},
{
"settings": [ "environment:production", "device:kindle" ],
"specs": {
"mainPage": {
"type": "TestMojit",
"config": {
"env": "I am in the production environment for Kindles."
}
}
}
},
]
The configuration gamma in the example defaults.json below is mapped to contexts for languages.
[
{
"settings": [ "master" ],
"config": {
"alpha" : "I am the first!",
"beta" : "I am the second!",
"gamma": "I am the third!"
}
},
{
"settings": [ "lang:de" ],
"config": {
"gamma": "I am (when lang=de is passed) the third!"
}
},
{
"settings": [ "lang:fr" ],
"config": {
"gamma": "defaults.json - (when lang=fr is passed) the third!"
}
}
]
[
{
"settings": [ "master" ],
"prod_route": {
"verbs": ["get"],
"path": "/",
"call": "hello.index"
}
},
{
"settings": [ "environment:development"],
"dev_route" : {
"verbs": ["get"],
"path" : "/testing",
"call" : "dev_hello.index"
}
}
]
You may dynamically change the configurations for any context by having a parent mojit execute a child mojit with new configurations. This is different than getting different configurations by requesting a new context or specifying a different base context. Regardless of the context being used, you can use the same context and change the configurations by executing a child mojit with new configurations. The parent mojit uses the execute method of the Composite addon to execute the child mojit. Let’s look at an example to see how it works.
In the example controller below, if the child parameter is found in the routing, query string, or request body, a child instance with its own configuration is executed, allowing the application to add new or change configurations of the current context.
YUI.add('TestMojit', function(Y) {
Y.mojito.controller = {
index: function(ac) {
var cfg = {
children: {
"one": {
"type": "Child",
"action": "index",
"config": {
"alpha": "Creating a new 'alpha' key or replacing the value of the alpha key mapped
to the context being used. The context, however, does not change."
}
}
}
};
var child = ac.params.getFromMerged('child');
if(child){
ac.composite.execute(cfg, function (data,meta){
ac.done(data["one"]);
});
}else{
ac.done(
'config key "alpha": ' + ac.config.get('alpha', '[alpha not found]')
);
}
}
};
}, '0.0.1', {requires: ['mojito']});
The Mojito framework defines default contexts that developers can map configurations to. These default contexts are defined in the file dimensions.json <https://github.com/yahoo/mojito/blob/develop/source/lib/dimensions.json>`_ found in the Mojito source code. Developers can create an application-level ``dimensions.json to define custom contexts that can be mapped to configurations as well.
The local dimensions.json replaces the Mojito’s dimensions.json, so to create custom contexts, you will need to copy Mojito’s dimension.json to your application directory and then add your custom contexts to the file. Defining and applying configurations for custom contexts is done in the same way as for default contexts.
Developers who create applications that require a degree of personalization that extends beyond language and device would be good candidates to create custom contexts. Before beginning to create your own dimensions.json file, you should review the Mojito Predefined Contexts to make sure that you truly need custom contexts.
The key-value pairs of the context are defined in the dimensions.json file in the application directory. Once contexts are defined in the dimensions.file, you can then map configurations to those contexts. If your application has configurations for a context that has not been defined by Mojito or at the application level in dimensions.json, an error will prevent you from starting the application.
In the dimension.json file, the dimensions array contains JavaScript objects that define the contexts. The keys of the context are the names of the objects, and the values are the object’s properties as seen below.
[
{
"dimensions":[
{
"region": {
"us": null,
"jp": null,
"cn": null
},
...
]
}
}
Based on the example dimensions.json below, the following are valid contexts:
[
{
"dimensions": [
...
{
"account_type": {
"basic": null,
"premium": null
}
},
{
"region":{
"us": null,
"gb": null,
"fr": null
}
}
...
}
]