1 | ---
|
2 | title: Kettle Configs and Applications
|
3 | layout: default
|
4 | category: Kettle
|
5 | ---
|
6 |
|
7 | The top-level structure of a Kettle application can be described by a "config" file in JSON or [JSON5](http://json5.org/) format. A Kettle "config"
|
8 | describes the configuration of a number of "Kettle apps" ([grade](http://docs.fluidproject.org/infusion/development/ComponentGrades.html) [`kettle.app`](RequestHandlersAndApps.md#kettle.app))
|
9 | hosted in a number of "Kettle servers" (grade [`kettle.server`](Servers.md)).
|
10 | The config JSON (or JSON5) file represents an Infusion [component tree](http://docs.fluidproject.org/infusion/development/HowToUseInfusionIoC.html). If you aren't familiar
|
11 | with the syntax and meaning of component trees, it is a good idea to browse the documentation, tutorials and examples at the
|
12 | Infusion [documentation site](http://docs.fluidproject.org/infusion/development/). Kettle components are currently derived from
|
13 | the base grade `fluid.component`, so you can ignore for these purposes the parts of the Infusion documentation relating to model and view components.
|
14 |
|
15 | Note that Kettle configs can represent any Infusion applications; they are not
|
16 | restricted to representing just Kettle applications. Their structure is
|
17 | freeform, other than the top level derived from `fluid.component`, and they may
|
18 | be used to encode any Infusion application as a component tree.
|
19 |
|
20 | ## A simple Kettle application
|
21 |
|
22 | 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
|
23 | same application represented in two forms in the [examples/simpleConfig](../examples/simpleConfig) directory.
|
24 |
|
25 | ```javascript
|
26 |
|
27 | fluid.defaults("examples.simpleConfig", {
|
28 | gradeNames: "fluid.component",
|
29 | components: {
|
30 | server: {
|
31 | type: "kettle.server",
|
32 | options: {
|
33 | port: 8081,
|
34 | components: {
|
35 | app: {
|
36 | type: "kettle.app",
|
37 | options: {
|
38 | requestHandlers: {
|
39 | getHandler: {
|
40 | "type": "examples.simpleConfig.handler",
|
41 | "route": "/handlerPath",
|
42 | "method": "get"
|
43 | }
|
44 | }
|
45 | }
|
46 | }
|
47 | }
|
48 | }
|
49 | }
|
50 | }
|
51 | });
|
52 |
|
53 | fluid.defaults("examples.simpleConfig.handler", {
|
54 | gradeNames: "kettle.request.http",
|
55 | invokers: {
|
56 | handleRequest: "examples.simpleConfig.handleRequest"
|
57 | }
|
58 | });
|
59 |
|
60 | examples.simpleConfig.handleRequest = function (request) {
|
61 | request.events.onSuccess.fire({
|
62 | message: "GET request received on path /handlerPath"
|
63 | });
|
64 | };
|
65 |
|
66 | // Construct the server using the above config
|
67 | examples.simpleConfig();
|
68 | ```
|
69 |
|
70 | The JSON "config" form of the application itself is held at [examples/simpleConfig/examples.simpleConfig.json](../examples/simpleConfig/examples.simpleConfig.json),
|
71 | which encodes the same information as in the first `fluid.defaults` call above. The definitions for request handlers such as `examples.simpleConfig.handler` and
|
72 | `examples.simpleConfig.handleRequest`, which in our sample are held in [examples/simpleConfig/simpleConfig-config-handler.js](../examples/simpleConfig/simpleConfig-config-handler.js),
|
73 | always need to be supplied in standard `.js` files required by the application – although future versions of Kettle
|
74 | may allow the defaults for the handler grade to be encoded in JSON. Consult the Infusion framework documentation on [grades](http://docs.fluidproject.org/infusion/development/ComponentGrades.html) if
|
75 | you are not familiar with this kind of configuration.
|
76 |
|
77 | You can try out these samples in [examples/simpleConfig](../examples/simpleConfig) by, for example, from that directory, typing `node simpleConfig-config-driver.js`. The last line of the driver files
|
78 | 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
|
79 | [testing](KettleTestingFramework.md) definitions. Later on, we will see how to issue formal test fixtures against this application by using the [Kettle testing framework](KettleTestingFramework.md).
|
80 |
|
81 | ## Starting an application encoded by a Kettle config
|
82 |
|
83 | An application encoded as a Kettle config can be started in a variety of ways,
|
84 | both programmatically and from the command line - as well as being easily embedded
|
85 | into other applications, whether they are Infusion component trees or raw Express apps.
|
86 |
|
87 | ### Starting a Kettle config programmatically
|
88 |
|
89 | 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
|
90 | following fields:
|
91 |
|
92 | |Member name| Type | Description |
|
93 | |-----------|------|-------------|
|
94 | |`configName`| `String` | The name of the config (the bare filename, minus any extension) which is to be loaded|
|
95 | |`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-)|
|
96 |
|
97 | `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.
|
98 |
|
99 | An alternative to `kettle.config.loadConfig` is `kettle.config.createDefaults`. This accepts the same arguments but simply loads the config as a [grade](http://docs.fluidproject.org/infusion/development/ComponentGrades.html)
|
100 | 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`](http://docs.fluidproject.org/infusion/development/CoreAPI.html#fluid-invokeglobalfunction-functionpath-args-) API, or else
|
101 | embed it in a wider application as a subcomponent.
|
102 |
|
103 | ### Starting a Kettle config from the command line
|
104 |
|
105 | 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.
|
106 | For example, from Kettle's top-level directory you can run
|
107 |
|
108 | ```
|
109 | node init.js <configPath> [<configName>]
|
110 | ````
|
111 |
|
112 | The `configPath` argument is required - its meaning is as given in the `configPath` option to `kettle.config.loadConfig` call described in the previous section.
|
113 |
|
114 | 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``.
|
115 | The meaning is as given in the `configName` option to `kettle.config.loadConfig` described in the previous section.
|
116 |
|
117 | For example, you can start the sample app from the [previous section](#a-simple-kettle-application) by running
|
118 | ```
|
119 | node init.js examples/simpleConfig examples.simpleConfig
|
120 | ```
|
121 | from the root directory of a Kettle checkout.
|
122 |
|
123 | ## Referring to external data via resolvers
|
124 |
|
125 | Kettle configs may refer to external data, for example encoded in environment
|
126 | variables, files, or other sources. This is achieved via Infusion's
|
127 | [expander](http://docs.fluidproject.org/infusion/development/ExpansionOfComponentOptions.html#expanders) syntax
|
128 | within the config, together with some standard built-in global functions
|
129 | representing _resolvers_.
|
130 |
|
131 | Here is an example of a little config which accepts a `url` property from an
|
132 | environment variable named `KETTLE_ENV_TEST`, via Infusion's [compact syntax](http://docs.fluidproject.org/infusion/development/ExpansionOfComponentOptions.html#compact-format-for-expanders):
|
133 |
|
134 | ```
|
135 | {
|
136 | "type": "fluid.component",
|
137 | "options": {
|
138 | "url": "@expand:kettle.resolvers.env(KETTLE_ENV_TEST)",
|
139 | }
|
140 | }
|
141 | ```
|
142 |
|
143 | If you need the ability for the target configuration to retain its default
|
144 | value in the case that the resolver value is missing, you should use
|
145 | Infusion's [options distributions](http://docs.fluidproject.org/infusion/development/IoCSS.html)
|
146 | to target the resolved value rather than writing it at top level within the config.
|
147 |
|
148 | ### kettle.resolvers.env
|
149 |
|
150 | `kettle.resolvers.env` is a global function which allows the resolution of
|
151 | environment variables. It accepts one argument, which is the name of the
|
152 | environment variable to be resolved. If the environment variable is not defined,
|
153 | the function returns `undefined`.
|
154 |
|
155 | ### kettle.resolvers.file
|
156 |
|
157 | `kettle.resolvers.file` is a global function which allows the resolution of
|
158 | material held in text files. It accepts one argument, which is the name of the
|
159 | file to be loaded. The filename may contain <a href="http://docs.fluidproject.org/infusion/development/NodeAPI.html#node-js-module-apis">module-relative path</a> such as <code>%kettle</code> to indicate a path relative to a module registered with Infusion.
|
160 |
|
161 | The file must contain text in the UTF-8 encoding. The contents of the file will be
|
162 | loaded via node's `fs.loadFileSync` API and returned as a string.
|
163 |
|
164 | ### kettle.resolvers.args
|
165 |
|
166 | `kettle.resolvers.args` is a global function which allows the resolution of
|
167 | the command-line arguments that the current node application was started with.
|
168 | It accepts zero or one arguments. If supplied no arguments, it will return the
|
169 | full value of node's `process.argv` argument array. If supplied one argument,
|
170 | it will return the value of using this to index into `process.argv`.
|
171 |
|
172 | ## Structure of a Kettle application's config
|
173 |
|
174 | In the previous section, we saw a [simple example](../examples/simpleConfig/examples.simpleConfig.json) of a JSON-formatted Kettle config, which declaratively encodes a Kettle application structure.
|
175 | 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](http://docs.fluidproject.org/infusion/development/ComponentGrades.html).
|
176 | 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
|
177 | 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.
|
178 |
|
179 | <table>
|
180 | <thead>
|
181 | <tr>
|
182 | <th colspan="3">Top-level members of a Kettle application's "config" configuration file</th>
|
183 | </tr>
|
184 | <tr>
|
185 | <th>Member</th>
|
186 | <th>Type</th>
|
187 | <th>Description</th>
|
188 | </tr>
|
189 | </thead>
|
190 | <tbody>
|
191 | <tr>
|
192 | <td><code>type</code></td>
|
193 | <td><code>String</code> (grade name)</td>
|
194 | <td>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 <code>.json</code> extension.</td>
|
195 | </tr>
|
196 | <tr>
|
197 | <td><code>options</code></td>
|
198 | <td><code>Object</code> (component options)</td>
|
199 | <td>The options for the application structure. These should start with the application's <code>gradeNames</code> which will usually just be <code>fluid.component</code>, and then continue with <code>components</code> designating the
|
200 | next level of containment of the application, the <code>kettle.server</code> level – see the next section on <a href="#containment-structure-of-a-kettle-application">containment structure of a Kettle application</a> for the full structure</td>
|
201 | </tr>
|
202 | <tr>
|
203 | <td><code>mergeConfigs</code> (optional)</td>
|
204 | <td><code>String/Array of String</code></td>
|
205 | <td>A filename (or array of these) of other config files which are to be included into this application. These names may begin with a <a href="http://docs.fluidproject.org/infusion/development/NodeAPI.html#node-js-module-apis">module-relative path</a>
|
206 | such as <code>%kettle</code> or else will be interpreted as
|
207 | paths relative to this config's location in the filesystem. The filenames may either end with a <code>.json</code> or a <code>.json5</code> extension representing configuration files in those formats, or the extension may be
|
208 | omitted in which case both of those extensions (in the order <code>.json</code>, <code>.json5</code>) will be tried as possibilities. Each config file will be loaded and resolved as a grade and then merged with the
|
209 | structure of this config (via an algorithm similar to <a href="https://api.jquery.com/jquery.extend/">jQuery.extend</a> – note that because of a current Infusion framework bug <a href="https://issues.fluidproject.org/browse/FLUID-5614">FLUID-5614</a>,
|
210 | all of the semantics of nested <a href="http://docs.fluidproject.org/infusion/development/OptionsMerging.html">options merging</a> will
|
211 | not be respected and the merging will occur in a simple-minded way below top level)</td>
|
212 | </tr>
|
213 | <tr>
|
214 | <td><code>loadConfigs</code> (optional)</td>
|
215 | <td><code>String/Array of String</code></td>
|
216 | <td>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 <a href="http://docs.fluidproject.org/infusion/development/NodeAPI.html#node-js-module-apis">module-relative path</a>
|
217 | such as <code>%kettle</code> or else will be interpreted as
|
218 | paths relative to this config's location in the filesystem. As with <code>mergeConfigs</code>, the filenames may be specified with <code>.json</code>, <code>.json5</code> or no extension. Each filename listed here will be loaded and resolved as a grade. The workflow is similar to that with <code>mergeConfigs</code>, only the grades represented in <code>loadConfigs</code>
|
219 | 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 <code>type</code> or <code>gradeNames</code> of a <a href="http://docs.fluidproject.org/infusion/development/SubcomponentDeclaration.html">subcomponent</a></td>
|
220 | </tr>
|
221 | <tr>
|
222 | <td><code>require</code> (optional)</td>
|
223 | <td><code>String/Array of String</code></td>
|
224 | <td>A <a href="https://nodejs.org/api/modules.html">module identifier</a> (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
|
225 | <a href="https://nodejs.org/api/modules.html"><code>require</code></a> operating from the config's directory (the <a href="https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders">global folder rules</a> will be ignored).
|
226 | These names may begin with a <a href="http://docs.fluidproject.org/infusion/development/NodeAPI.html#node-js-module-apis">module-relative path</a> such as <code>%kettle</code> to indicate a path relative to a module registered with Infusion.</td>
|
227 | </tr>
|
228 | </tbody>
|
229 | </table>
|
230 |
|
231 |
|
232 | ## Containment structure of a Kettle application
|
233 |
|
234 | The overall structure of a Kettle application within its config shows a 4-level pattern:
|
235 |
|
236 | * 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
|
237 | * At 2nd level, one or more Kettle servers – these have the grade [`kettle.server`](Servers.md) – in the case there is just one server it is conventionally named `server`
|
238 | * At 3rd level, one more Kettle apps – these have the grade [`kettle.app`](RequestHandlersAndApps.md#kettle.app) – this is the level at which independently mountable segments of applications are grouped (an app is a grouping of handlers)
|
239 | * At 4th level, one or more Kettle request handlers – these have the grade [`kettle.request`](RequestHandlersAndApps.md#kettle.request) – each of these handles one endpoint (HTTP or WebSockets) routed by URL and request method
|
240 |
|
241 | 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
|
242 | customise and reassort groups of handlers and servers from application to application.
|
243 |
|
244 | 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
|
245 | levels below a server. However, request handlers must be defined as direct children of their parent apps, in the options section named `requestHandlers`.
|
246 |
|
247 | ## Further reading
|
248 |
|
249 | Go on to [Kettle servers](Servers.md) to learn about the 2nd level of containment, and [Kettle request handlers and apps](RequestHandlersAndApps.md) to learn about levels 3 and 4.
|
250 |
|
\ | No newline at end of file |