title | layout | category |
---|---|---|
Kettle Configs and Applications |
default |
Kettle |
The top-level structure of a Kettle application can be described by a "config" file in JSON or
JSON5 format. A Kettle "config" describes the configuration of a number of "Kettle apps"
(grade
kettle.app
) hosted in a number of "Kettle servers"
(grade kettle.server
).
The config JSON (or JSON5) file represents an Infusion
component tree. If you aren't familiar
with the syntax and meaning of component trees, it is a good idea to browse the documentation, tutorials and examples
at the Infusion documentation site. Kettle components are
currently derived from the base grade fluid.component
, so you can ignore for these purposes the parts of the Infusion
documentation relating to model and view components.
Note that Kettle configs can represent any Infusion applications; they are not
restricted to representing just Kettle applications. Their structure is
freeform, other than the top level derived from fluid.component
, and they may
be used to encode any Infusion application as a component tree.
In this section, we will construct a simple Kettle application within JavaScript code, to produce a self-contained example. You can find and try out this same application represented in two forms in the examples/simpleConfig directory.
fluid.defaults("examples.simpleConfig", {
gradeNames: "fluid.component",
components: {
server: {
type: "kettle.server",
options: {
port: 8081,
components: {
app: {
type: "kettle.app",
options: {
requestHandlers: {
getHandler: {
"type": "examples.simpleConfig.handler",
"route": "/handlerPath",
"method": "get"
}
}
}
}
}
}
}
}
});
fluid.defaults("examples.simpleConfig.handler", {
gradeNames: "kettle.request.http",
invokers: {
handleRequest: "examples.simpleConfig.handleRequest"
}
});
examples.simpleConfig.handleRequest = function (request) {
request.events.onSuccess.fire({
message: "GET request received on path /handlerPath"
});
};
// Construct the server using the above config
examples.simpleConfig();
The JSON "config" form of the application itself is held at
examples/simpleConfig/examples.simpleConfig.json,
which encodes the same information as in the first fluid.defaults
call above. The definitions for request handlers
such as examples.simpleConfig.handler
and examples.simpleConfig.handleRequest
, which in our sample are held in
examples/simpleConfig/simpleConfig-config-handler.js,
always need to be supplied in standard .js
files required by the application – although future versions of Kettle
may allow the defaults for the handler grade to be encoded in JSON. Consult the Infusion framework documentation on
grades if you are not familiar with this
kind of configuration.
You can try out these samples in examples/simpleConfig by, for example, from that
directory, typing node simpleConfig-config-driver.js
. The last line of the driver files load a common module,
simpleConfig-client.js
which tests the server by firing an HTTP request to it and logging the payload – this uses
one of the HTTP client drivers taken from Kettle's
testing definitions. Later on, we will see how to issue formal test fixtures against this
application by using the Kettle testing framework.
An application encoded as a Kettle config can be started in a variety of ways, both programmatically and from the command line - as well as being easily embedded into other applications, whether they are Infusion component trees or raw Express apps.
Kettle includes a driver function, kettle.config.loadConfig
which will load and run a Kettle application defined as a
JSON or JSON5 file in the filesystem. It accepts an options
structure which includes the
following fields:
Member name | Type | Description |
---|---|---|
configName |
String |
The name of the config (the bare filename, minus any extension) which is to be loaded |
configPath |
String |
The directory holding the config. This path may start with a symbolic module reference, e.g. of the form `%kettle`, to a module which has been registered using Infusion's module API [`fluid.module.register`](http://docs.fluidproject.org/infusion/development/NodeAPI.html#fluid-module-register-name-basedir-modulerequire-) |
kettle.config.loadConfig
will return the (Infusion) component instance of the initialised application. You could use
this, for example, to terminate the application using its destroy()
method.
An alternative to kettle.config.loadConfig
is kettle.config.createDefaults
. This accepts the same arguments but
simply loads the config as a grade
rather than instantiating it as well. The return value from kettle.config.loadConfig
is the grade name of the
application. You can construct this application later by use of Infusion's
invokeGlobalFunction
API, or else embed it in a wider application as a subcomponent.
Kettle includes a top-level driver file named init.js
which will accept values from the command line and the
environment variable NODE_ENV
in order to determine which application config to start.
For example, from Kettle's top-level directory you can run
node init.js <configPath> [<configName>]
The configPath
argument is required - its meaning is as given in the configPath
option to
kettle.config.loadConfig
call described in the previous section.
The configName
argument is optional. If this value is not supplied at the command line, it will be read from the
environment variable NODE_ENV
.
The meaning is as given in the configName
option to kettle.config.loadConfig
described in the previous section.
For example, you can start the sample app from the previous section by running
node init.js examples/simpleConfig examples.simpleConfig
from the root directory of a Kettle checkout.
Kettle configs may refer to external data, for example encoded in environment variables, files, or other sources. This is achieved via Infusion's expander syntax within the config, together with some standard built-in global functions representing resolvers.
Here is an example of a little config which accepts a url
property from an
environment variable named KETTLE_ENV_TEST
, via Infusion's
compact syntax:
{
"type": "fluid.component",
"options": {
"url": "@expand:kettle.resolvers.env(KETTLE_ENV_TEST)"
}
}
If you need the ability for the target configuration to retain its default value in the case that the resolver value is missing, you should use Infusion's options distributions to target the resolved value rather than writing it at top level within the config.
kettle.resolvers.env
is a global function which allows the resolution of
environment variables. It accepts one argument, which is the name of the
environment variable to be resolved. If the environment variable is not defined,
the function returns undefined
.
kettle.resolvers.file
is a global function which allows the resolution of
material held in text files. It accepts one argument, which is the name of the
file to be loaded. The filename may contain
module-relative path such as
%kettle
to indicate a path relative to a module registered with Infusion.
The file must contain text in the UTF-8 encoding. The contents of the file will be
loaded via node's fs.loadFileSync
API and returned as a string.
kettle.resolvers.args
is a global function which allows the resolution of
the command-line arguments that the current node application was started with.
It accepts zero or one arguments. If supplied no arguments, it will return the
full value of node's process.argv
argument array. If supplied one argument,
it will return the value of using this to index into process.argv
.
In the previous section, we saw a simple example of a
JSON-formatted Kettle config, which declaratively encodes a Kettle application structure.
In this section we describe the top-level members of this structure, and in the next secion we'll look at the
containment structure in terms of grades.
In the rest of this document we'll describe the options accepted by the various grades which make up a Kettle
application (kettle.server
, kettle.app
, kettle.middleware
and kettle.request
). The structure of our
minimal application will serve as a general template – the full definition of a Kettle application consists of a
config, plus definitions of request handler grades plus implementations of request handler functions.
Top-level members of a Kettle application's "config" configuration file | ||
---|---|---|
Member | Type | Description |
type |
String (grade name) |
The type name for this config. This should be a fully-qualified grade name – it is suggested that it
agree with the file name of the config file without the .json extension. |
options |
Object (component options) |
The options for the application structure. These should start with the application's
gradeNames which will usually just be fluid.component , and then continue
with components designating the next level of containment of the application, the
kettle.server level – see the next section on
containment structure of a Kettle
application for the full structure |
mergeConfigs (optional) |
String/Array of String |
A filename (or array of these) of other config files which are to be included into this application.
These names may begin with a
module-relative
path such as %kettle or else will be interpreted as
paths relative to this config's location in the filesystem. The filenames may either end with a
.json or a .json5 extension representing configuration files in those formats,
or the extension may be omitted in which case both of those extensions (in the order .json ,
.json5 ) will be tried as possibilities. Each config file will be loaded and resolved as a
grade and then merged with the structure of this config (via an algorithm similar to
jQuery.extend – note that because of a current
Infusion framework bug FLUID-5614,
all of the semantics of nested
options merging will
not be respected and the merging will occur in a simple-minded way below top level) |
loadConfigs (optional) |
String/Array of String |
A filename (or array of these) of other config files which will be loaded before this config is
interpreted. These names may begin with a
module-relative
path such as %kettle or else will be interpreted as paths relative to this config's
location in the filesystem. As with mergeConfigs , the filenames may be specified with
.json , .json5 or no extension. Each filename listed here will be loaded and
resolved as a grade. The workflow is similar to that with mergeConfigs , only the grades
represented in loadConfigs will not be automatically merged with the current config as parent
grades. Instead, the user is free to refer to them as required - for example as the type or
gradeNames of a
subcomponent |
require (optional) |
String/Array of String |
A module identifier (or array of these) that will be
loaded when this config is loaded. These modules will be loaded as if by the standard node.js API
require operating from the config's
directory (the
global folder
rules will be ignored).
These names may begin with a
module-relative
path such as %kettle to indicate a path relative to a module registered with Infusion. |
The overall structure of a Kettle application within its config shows a 4-level pattern:
- At top level, the application container – this has the simple grade
fluid.component
and does not carry any functionality – it is simply used for grouping the definitions at the next level- At 2nd level, one or more Kettle servers – these have the grade
kettle.server
– in the case there is just one server it is conventionally namedserver
- At 3rd level, one more Kettle apps – these have the grade
kettle.app
– this is the level at which independently mountable segments of applications are grouped (an app is a grouping of handlers)- At 4th level, one or more Kettle request handlers – these have the grade
kettle.request
– each of these handles one endpoint (HTTP or WebSockets) routed by URL and request method
- At 4th level, one or more Kettle request handlers – these have the grade
- At 3rd level, one more Kettle apps – these have the grade
- At 2nd level, one or more Kettle servers – these have the grade
This expression is much more verbose in simple cases than the traditional raw use of express apps, but in larger and more complex applications this verbosity is amortised, with the ability to easily customise and reassort groups of handlers and servers from application to application.
Note that the containment relationships between the top 3 levels need not be direct – servers may be nested any number
of levels below the config root, and apps may be nested any number of levels below a server. However, request handlers
must be defined as direct children of their parent apps, in the options section named requestHandlers
.
Go on to Kettle servers to learn about the 2nd level of containment, and Kettle request handlers and apps to learn about levels 3 and 4.