/
demoApp.js
189 lines (138 loc) · 6.22 KB
/
demoApp.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// simplistic example application for guar API framework
var _ = require('lodash');
var guar = require('..');
var express = require('express');
var bodyParser = require('body-parser');
var debug;
module.exports = function(app, appConfig) {
app = app || express();
app.use(bodyParser.json({limit: "500kb"}));
app.use(bodyParser.urlencoded({extended: true, limit: "500kb"}));
appConfig = appConfig || {};
var mergedConfig = _.merge({}, config, appConfig);
// initializing these here because they need a reference to app
mergedConfig.middlewares.preData = demoPreApi(app);
mergedConfig.apiCallBefore = demoApiCallBefore(app);
guar(app, mergedConfig);
app.use(handleErrors);
debug = (appConfig.customDebug) ? appConfig.customDebug('guar->demoApp')
: function(msg) { if (mergedConfig.debugToConsole) console.log('guar->demoApp: ' + msg); };
return app;
};
// since we're not sure where this demo app is being invoked
var myDir = __filename.substr(0,__filename.length-11);
// override nodulejs defaults
var config = {
// path(s) to look for your nodules
dirs: [
{ path: myDir, exclude: ['emoApp.js', '.test.js'] }, // exclude both demo apps, can be full or partal match
],
// set to true or or use customDebug: function(identifier) { return function(msg){... your debug function here ...} }
debugToConsole: true,
/////////////////////////////////////////////////////////////
/// CUSTOM MIDDLEWARE SPLICED IN-BETWEEN YUKON MIDDLEWARE ///
/////////////////////////////////////////////////////////////
middlewares: {
// middleware nvoked before guar preData, which calls nodule.preProcessor
start: demoStart,
// middleware invoked before guar doApi, which makes all API calls in parallel and waits for all of them to return
preData: null, // set in init since it needs app
// middleware invoked before guar postData, which calls nodule.postProcessor
postData: demoPostApi,
// middleware invoked before guar finish, which sends JSON
finish: demoFinish,
},
///////////////////////////////////////////////////
/// FUNCTIONS INVOKED PRE AND POST API BY YUKON ///
///////////////////////////////////////////////////
// invoked before every API call
apiCallBefore: null, // set in init since it needs app
// invoked after every API call - success or error
apiCallback: demoApiCallback,
//////////////////////////////////////////////////////////
/// CUSTOM NODULE PROPERTIES ON TOP OF YUKON FRAMEWORK ///
//////////////////////////////////////////////////////////
noduleDefaults: {
suppressNav: false, // set true to skip global nav API call on HTML nodules
},
///////////////////////////////////////////////////////
/// CUSTOM API PROPERTIES ON TOP OF YUKON FRAMEWORK ///
///////////////////////////////////////////////////////
apiDefaults: {
handleError: null, // set true to have nodule handle error instead of calling next(error)
}
};
function demoStart(req, res, next) {
debug("demoStart called");
res.locals.pretty = true; // jade pretty setting - turn off at the component level if necessary
// example of setting nodule property globally
if (req.nodule.contentType !== 'html' && req.path.indexOf('/json/') === 0)
req.nodule.contentType = 'json';
// example of app-level logic - simple device detection (used throughout middleware examples)
if (req.headers['user-agent'].match(/android/i))
req.deviceType = 'Android';
else if (req.headers['user-agent'].match(/iphone/i))
req.deviceType = 'iPhone';
else if (req.headers['user-agent'].match(/ipad/i))
req.deviceType = 'iPad';
else
req.deviceType = 'web';
next();
}
function demoPreApi(app) {
return function(req, res, next) {
debug("demoPreApi called");
// example of how to *use stub/set nodule property* based on individual nodule or global config setting
req.nodule.useStub = req.nodule.useStub || app.locals.useStubs;
// example of adding global api call at app-level
if (req.nodule.contentType !== 'json' && !req.nodule.suppressNav)
req.nodule.apiCalls.globalNav = {path:'/api/globalnav'};
next();
};
}
function demoPostApi(req, res, next) {
debug("demoPostApi called");
// example of adding functionality globally after the API but before the nodule post processor is called
if (res.locals.globalNav)
res.locals.globalNav.deviceType = req.deviceType;
next();
}
function demoFinish(req, res, next) {
debug("demoFinish called");
// example of adding functionality before the framework calls res.render or res.send
if (req.nodule.contentType !== 'json')
res.locals.responseData.deviceType = req.deviceType;
else
res.locals.responseData.clientData = {deviceType: req.deviceType};
next();
}
function demoApiCallBefore(app) {
return function(callArgs, req, res) {
debug('callling API - ' + callArgs.verb + ': ' + callArgs.path);
// example of using global property if not specified
callArgs.host = callArgs.host ? 'http://' + callArgs.host : req.headers.host; // using run-time host for API sims
// example of custom API headers and app-specific behavior before calling API
callArgs.customHeaders.push({ name: 'x-device-type', value: req.deviceType});
};
}
function demoApiCallback(callArgs, req, res, next) {
if (callArgs.apiError && !callArgs.handleError) {
debug(callArgs.apiError.stack || callArgs.apiError);
next(new Error('API failed for '+callArgs.path +': '+callArgs.apiError));
}
else {
var msg = "RESPONSE FROM "+callArgs.apiResponse.req.path+": statusCode=" + callArgs.apiResponse.statusCode;
debug(msg);
// example of app-level logic on every api response (remember there can be multiple API calls per request)
res.locals[callArgs.namespace].systemMsg = msg;
// used by kitchen sink to test if API custom headers are being set
if (callArgs.apiResponse.req._headers)
res.locals[callArgs.namespace].customHeaders = callArgs.apiResponse.req._headers;
next();
}
}
function handleErrors(err, req, res, next) {
debug('handleErrors called');
debug(err.stack || err.toString());
res.status(500).send('<h1>500 Server Error</h1><h3><pre>' + (err.stack || err) + '</pre></h3>');
}