UNPKG

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