jxp 2.12.3 → 2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/setup.js +3 -2
- package/docs/caching.md +12 -0
- package/libs/cache.js +47 -0
- package/libs/jxp.js +26 -5
- package/package.json +2 -1
- package/test/test.js +56 -15
package/bin/setup.js
CHANGED
|
@@ -81,8 +81,9 @@ async function main() {
|
|
|
81
81
|
await mkdir(path.join(destination_path, "models"));
|
|
82
82
|
await mkdir(path.join(destination_path, "config"));
|
|
83
83
|
await mkdir(path.join(destination_path, "logs"));
|
|
84
|
+
await mkdir(path.join(destination_path, "libs"));
|
|
84
85
|
await cp_replace("../config_sample.json", path.join(destination_path, "config/default.json"), opts, "{", "}");
|
|
85
|
-
await cp_replace("./server.js", path.join(destination_path, "bin/server.js"), { "../libs/jxp": "jxp" });
|
|
86
|
+
await cp_replace("./server.js", path.join(destination_path, "bin/server.js"), { "../libs/jxp": "jxp/libs/jxp", "../libs/connection_string": "jxp/libs/connection_string" });
|
|
86
87
|
for (let model of models) {
|
|
87
88
|
await cp("../models/" + model + "_model.js", path.join(destination_path, "models/" + model + "_model.js"));
|
|
88
89
|
}
|
|
@@ -149,7 +150,7 @@ async function main() {
|
|
|
149
150
|
* Copy from to replacing text as we go
|
|
150
151
|
*
|
|
151
152
|
*/
|
|
152
|
-
function cp_replace(from, to, opts, startEnclosure, endEnclosure) {
|
|
153
|
+
function cp_replace(from, to, opts, startEnclosure = "", endEnclosure = "") {
|
|
153
154
|
startEnclosure = startEnclosure || "";
|
|
154
155
|
endEnclosure = endEnclosure || "";
|
|
155
156
|
from = path.join(__dirname, from);
|
package/docs/caching.md
ADDED
package/libs/cache.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const NodeCache = require('node-cache');
|
|
2
|
+
const config = require('config');
|
|
3
|
+
const cache = new NodeCache({ stdTTL: config.cache?.ttl || 5 * 60 });
|
|
4
|
+
|
|
5
|
+
const generateKey = (req) => {
|
|
6
|
+
const url = req.url
|
|
7
|
+
return url
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const set = (req, res, next) => {
|
|
11
|
+
if (!config.cache?.enabled) return next();
|
|
12
|
+
const key = generateKey(req)
|
|
13
|
+
cache.set(key, res.result)
|
|
14
|
+
next()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const get = (req, res, next) => {
|
|
18
|
+
if (!config.cache?.enabled) return next();
|
|
19
|
+
const key = generateKey(req)
|
|
20
|
+
const cached = cache.get(key)
|
|
21
|
+
if (cached) {
|
|
22
|
+
res.header('jxp-cache', 'hit')
|
|
23
|
+
res.result = cached
|
|
24
|
+
return res.send(res.result)
|
|
25
|
+
}
|
|
26
|
+
res.header('jxp-cache', 'miss')
|
|
27
|
+
next()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const clear = (req, res, next) => {
|
|
31
|
+
if (!config.cache?.enabled) return next();
|
|
32
|
+
cache.flushAll()
|
|
33
|
+
next()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const stats = (req, res, next) => {
|
|
37
|
+
if (!config.cache?.enabled) return {};
|
|
38
|
+
res.result = cache.getStats()
|
|
39
|
+
next()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = {
|
|
43
|
+
set,
|
|
44
|
+
get,
|
|
45
|
+
clear,
|
|
46
|
+
stats
|
|
47
|
+
}
|
package/libs/jxp.js
CHANGED
|
@@ -15,6 +15,7 @@ const modeldir = require("./modeldir");
|
|
|
15
15
|
const query_manipulation = require("./query_manipulation");
|
|
16
16
|
const corsMiddleware = require('restify-cors-middleware2');
|
|
17
17
|
const json2csv = require('json2csv').parse;
|
|
18
|
+
const cache = require("./cache");
|
|
18
19
|
global.JXPSchema = require("./schema");
|
|
19
20
|
|
|
20
21
|
var models = {};
|
|
@@ -202,7 +203,7 @@ const actionGetOne = async (req, res) => {
|
|
|
202
203
|
console.time(opname);
|
|
203
204
|
try {
|
|
204
205
|
const data = await getOne(req.Model, req.params.item_id, req.query, { user: res.user });
|
|
205
|
-
res.
|
|
206
|
+
res.result = { data };
|
|
206
207
|
if (debug) console.timeEnd(opname);
|
|
207
208
|
} catch(err) {
|
|
208
209
|
console.error(new Date(), err);
|
|
@@ -908,7 +909,9 @@ const JXP = function(options) {
|
|
|
908
909
|
security.login,
|
|
909
910
|
security.auth,
|
|
910
911
|
config.pre_hooks.get,
|
|
912
|
+
cache.get,
|
|
911
913
|
actionGet,
|
|
914
|
+
cache.set,
|
|
912
915
|
outputJSON
|
|
913
916
|
);
|
|
914
917
|
server.get(
|
|
@@ -916,8 +919,12 @@ const JXP = function(options) {
|
|
|
916
919
|
middlewareModel,
|
|
917
920
|
security.login,
|
|
918
921
|
security.auth,
|
|
922
|
+
cache.get,
|
|
919
923
|
config.pre_hooks.getOne,
|
|
920
|
-
|
|
924
|
+
cache.get,
|
|
925
|
+
actionGetOne,
|
|
926
|
+
cache.set,
|
|
927
|
+
outputJSON
|
|
921
928
|
);
|
|
922
929
|
server.post(
|
|
923
930
|
"/api/:modelname",
|
|
@@ -927,6 +934,7 @@ const JXP = function(options) {
|
|
|
927
934
|
middlewarePasswords,
|
|
928
935
|
config.pre_hooks.post,
|
|
929
936
|
actionPost,
|
|
937
|
+
cache.clear,
|
|
930
938
|
(req, res, next) => {
|
|
931
939
|
next();
|
|
932
940
|
},
|
|
@@ -940,6 +948,7 @@ const JXP = function(options) {
|
|
|
940
948
|
middlewareCheckAdmin,
|
|
941
949
|
config.pre_hooks.put,
|
|
942
950
|
actionPut,
|
|
951
|
+
cache.clear,
|
|
943
952
|
);
|
|
944
953
|
server.del(
|
|
945
954
|
"/api/:modelname/:item_id",
|
|
@@ -948,6 +957,7 @@ const JXP = function(options) {
|
|
|
948
957
|
security.auth,
|
|
949
958
|
config.pre_hooks.delete,
|
|
950
959
|
actionDelete,
|
|
960
|
+
cache.clear,
|
|
951
961
|
);
|
|
952
962
|
|
|
953
963
|
// Count
|
|
@@ -957,7 +967,9 @@ const JXP = function(options) {
|
|
|
957
967
|
security.login,
|
|
958
968
|
security.auth,
|
|
959
969
|
config.pre_hooks.get,
|
|
970
|
+
cache.get,
|
|
960
971
|
actionCount,
|
|
972
|
+
cache.set,
|
|
961
973
|
outputJSON
|
|
962
974
|
);
|
|
963
975
|
|
|
@@ -1009,6 +1021,7 @@ const JXP = function(options) {
|
|
|
1009
1021
|
middlewareCheckAdmin,
|
|
1010
1022
|
config.pre_hooks.update,
|
|
1011
1023
|
actionUpdate,
|
|
1024
|
+
cache.clear,
|
|
1012
1025
|
);
|
|
1013
1026
|
|
|
1014
1027
|
/* Batch routes - ROLLED BACK FOR NOW */
|
|
@@ -1020,21 +1033,24 @@ const JXP = function(options) {
|
|
|
1020
1033
|
middlewareModel,
|
|
1021
1034
|
security.login,
|
|
1022
1035
|
security.auth,
|
|
1023
|
-
actionCall
|
|
1036
|
+
actionCall,
|
|
1037
|
+
cache.clear,
|
|
1024
1038
|
);
|
|
1025
1039
|
server.post(
|
|
1026
1040
|
"/call/:modelname/:method_name",
|
|
1027
1041
|
middlewareModel,
|
|
1028
1042
|
security.login,
|
|
1029
1043
|
security.auth,
|
|
1030
|
-
actionCall
|
|
1044
|
+
actionCall,
|
|
1045
|
+
cache.clear,
|
|
1031
1046
|
);
|
|
1032
1047
|
server.get(
|
|
1033
1048
|
"/call/:modelname/:item_id/:method_name",
|
|
1034
1049
|
middlewareModel,
|
|
1035
1050
|
security.login,
|
|
1036
1051
|
security.auth,
|
|
1037
|
-
actionCallItem
|
|
1052
|
+
actionCallItem,
|
|
1053
|
+
cache.clear,
|
|
1038
1054
|
);
|
|
1039
1055
|
|
|
1040
1056
|
/* Login and authentication */
|
|
@@ -1081,6 +1097,11 @@ const JXP = function(options) {
|
|
|
1081
1097
|
|
|
1082
1098
|
/* Websocket */
|
|
1083
1099
|
server.on("upgrade", ws.upgrade)
|
|
1100
|
+
|
|
1101
|
+
/* Cache */
|
|
1102
|
+
server.get("/cache/stats", cache.stats, outputJSON);
|
|
1103
|
+
server.get("/cache/clear", cache.clear, outputJSON);
|
|
1104
|
+
|
|
1084
1105
|
return server;
|
|
1085
1106
|
};
|
|
1086
1107
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jxp",
|
|
3
3
|
"description:": "An opinionated RESTful API library based on Mongoose and Restify. Make an API by just writing Mongoose models.",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.13.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"main": "libs/jxp.js",
|
|
7
7
|
"scripts": {
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"mongoose": "6.8.4",
|
|
46
46
|
"mongoose-friendly": "^0.1.4",
|
|
47
47
|
"morgan": "^1.10.0",
|
|
48
|
+
"node-cache": "^5.1.2",
|
|
48
49
|
"nodemailer": "^6.9.0",
|
|
49
50
|
"nodemailer-smtp-transport": "^2.7.4",
|
|
50
51
|
"path": "^0.12.7",
|
package/test/test.js
CHANGED
|
@@ -127,7 +127,6 @@ describe('Test', () => {
|
|
|
127
127
|
.get("/api/user")
|
|
128
128
|
.auth(init.email, init.password)
|
|
129
129
|
.end((err, res) => {
|
|
130
|
-
// console.log(res.body);
|
|
131
130
|
res.should.have.status(200);
|
|
132
131
|
res.body.data.should.be.an('array');
|
|
133
132
|
done();
|
|
@@ -166,7 +165,6 @@ describe('Test', () => {
|
|
|
166
165
|
chai.request(server)
|
|
167
166
|
.get(`/api/user`)
|
|
168
167
|
.end((err, res) => {
|
|
169
|
-
// console.log(res.body);
|
|
170
168
|
res.should.have.status(403);
|
|
171
169
|
done();
|
|
172
170
|
});
|
|
@@ -374,7 +372,6 @@ describe('Test', () => {
|
|
|
374
372
|
.get(`/api/test/${post_id}?populate=link`)
|
|
375
373
|
.auth(init.email, init.password)
|
|
376
374
|
.end((err, res) => {
|
|
377
|
-
// console.log(res.body);
|
|
378
375
|
res.should.have.status(200);
|
|
379
376
|
res.body.should.have.property("data");
|
|
380
377
|
res.body.data.should.have.property("link");
|
|
@@ -391,7 +388,6 @@ describe('Test', () => {
|
|
|
391
388
|
.get(`/api/test/${post_id}?populate=other_link`)
|
|
392
389
|
.auth(init.email, init.password)
|
|
393
390
|
.end((err, res) => {
|
|
394
|
-
// console.log(res.body);
|
|
395
391
|
res.should.have.status(200);
|
|
396
392
|
res.body.should.have.property("data");
|
|
397
393
|
res.body.data.should.have.property("other_link")
|
|
@@ -408,7 +404,6 @@ describe('Test', () => {
|
|
|
408
404
|
.get(`/api/test?autopopulate=true`)
|
|
409
405
|
.auth(init.email, init.password)
|
|
410
406
|
.end((err, res) => {
|
|
411
|
-
// console.log(res.body);
|
|
412
407
|
res.should.have.status(200);
|
|
413
408
|
res.body.data[0].should.have.property("link")
|
|
414
409
|
res.body.data[0].link.should.be.an('object');
|
|
@@ -426,7 +421,6 @@ describe('Test', () => {
|
|
|
426
421
|
.get(`/api/test/${post_id}?autopopulate=true`)
|
|
427
422
|
.auth(init.email, init.password)
|
|
428
423
|
.end((err, res) => {
|
|
429
|
-
// console.log(res.body);
|
|
430
424
|
res.should.have.status(200);
|
|
431
425
|
res.body.data.should.have.property("link")
|
|
432
426
|
res.body.data.link.should.be.an('object');
|
|
@@ -444,7 +438,6 @@ describe('Test', () => {
|
|
|
444
438
|
.get(`/api/test/${post_id}?populate=link`)
|
|
445
439
|
.auth(init.email, init.password)
|
|
446
440
|
.end((err, res) => {
|
|
447
|
-
console.log(res.body);
|
|
448
441
|
res.should.have.status(200);
|
|
449
442
|
res.body.should.have.property("data");
|
|
450
443
|
res.body.data.should.have.property("link")
|
|
@@ -573,7 +566,6 @@ describe('Test', () => {
|
|
|
573
566
|
.get(`/api/test?populate=array_link`)
|
|
574
567
|
.auth(init.email, init.password)
|
|
575
568
|
.end((err, res) => {
|
|
576
|
-
// console.log(res.body);
|
|
577
569
|
res.should.have.status(200);
|
|
578
570
|
res.body.data[0].should.have.property("array_link");
|
|
579
571
|
res.body.data[0].array_link.should.be.an("array");
|
|
@@ -727,7 +719,6 @@ describe('Test', () => {
|
|
|
727
719
|
.send({ query })
|
|
728
720
|
.end((err, res) => {
|
|
729
721
|
res.should.have.status(200);
|
|
730
|
-
// console.log(res.body);
|
|
731
722
|
res.body.data.should.be.an('array');
|
|
732
723
|
res.body.data[0].should.have.property("_id");
|
|
733
724
|
res.body.data[0].should.have.property("count");
|
|
@@ -876,7 +867,6 @@ describe('Test', () => {
|
|
|
876
867
|
.del(`/api/test/${post_id}`)
|
|
877
868
|
.auth(init.email, init.password)
|
|
878
869
|
.end((err, res) => {
|
|
879
|
-
// console.log(res.body);
|
|
880
870
|
res.should.have.status(200);
|
|
881
871
|
res.body.status.should.equal('ok');
|
|
882
872
|
done();
|
|
@@ -887,7 +877,6 @@ describe('Test', () => {
|
|
|
887
877
|
.get(`/api/test/${post_id}`)
|
|
888
878
|
.auth(init.email, init.password)
|
|
889
879
|
.end((err, res) => {
|
|
890
|
-
// console.log(res.body);
|
|
891
880
|
res.should.have.status(404);
|
|
892
881
|
res.body.message.should.equal(`Document ${post_id} is deleted on Test`);
|
|
893
882
|
res.body.code.should.equal('NotFound');
|
|
@@ -992,7 +981,6 @@ describe('Test', () => {
|
|
|
992
981
|
.auth(init.email, init.password)
|
|
993
982
|
.end((err, res) => {
|
|
994
983
|
res.should.have.status(409);
|
|
995
|
-
// console.log(res.body.message);
|
|
996
984
|
res.body.message.should.equal(`Parent link item exists in test/link_id`);
|
|
997
985
|
done();
|
|
998
986
|
});
|
|
@@ -1002,7 +990,6 @@ describe('Test', () => {
|
|
|
1002
990
|
.del(`/api/link/${link_id}?_cascade=1`)
|
|
1003
991
|
.auth(init.email, init.password)
|
|
1004
992
|
.end((err, res) => {
|
|
1005
|
-
// console.log(res.body, res.status);
|
|
1006
993
|
res.should.have.status(200);
|
|
1007
994
|
res.body.status.should.equal('ok');
|
|
1008
995
|
done();
|
|
@@ -1133,12 +1120,66 @@ describe('Test', () => {
|
|
|
1133
1120
|
bar: "Throw an error"
|
|
1134
1121
|
})
|
|
1135
1122
|
.end((err, res) => {
|
|
1136
|
-
// console.log(res.body);
|
|
1137
|
-
console.log(res.headers);
|
|
1138
1123
|
res.should.have.status(418);
|
|
1139
1124
|
res.body.message.should.equal(`I'm a teapot`);
|
|
1140
1125
|
done();
|
|
1141
1126
|
});
|
|
1142
1127
|
})
|
|
1143
1128
|
});
|
|
1129
|
+
|
|
1130
|
+
describe("Caching", () => {
|
|
1131
|
+
it ("should give us cache stats", (done) => {
|
|
1132
|
+
chai.request(server)
|
|
1133
|
+
.get("/cache/stats")
|
|
1134
|
+
.end((err, res) => {
|
|
1135
|
+
// console.log(res.body);
|
|
1136
|
+
res.should.have.status(200);
|
|
1137
|
+
res.body.should.have.property("hits");
|
|
1138
|
+
done();
|
|
1139
|
+
});
|
|
1140
|
+
})
|
|
1141
|
+
it ("should clear the cache stats", (done) => {
|
|
1142
|
+
chai.request(server)
|
|
1143
|
+
.get("/cache/clear")
|
|
1144
|
+
.end((err, res) => {
|
|
1145
|
+
console.log(res.body);
|
|
1146
|
+
res.should.have.status(200);
|
|
1147
|
+
done();
|
|
1148
|
+
});
|
|
1149
|
+
});
|
|
1150
|
+
it ("should get an uncached request", (done) => {
|
|
1151
|
+
chai.request(server)
|
|
1152
|
+
.get("/api/test")
|
|
1153
|
+
.auth(init.email, init.password)
|
|
1154
|
+
.end((err, res) => {
|
|
1155
|
+
res.should.have.status(200);
|
|
1156
|
+
res.headers.should.have.property("jxp-cache");
|
|
1157
|
+
res.headers["jxp-cache"].should.equal("miss");
|
|
1158
|
+
done();
|
|
1159
|
+
});
|
|
1160
|
+
});
|
|
1161
|
+
it ("should get an cached request", (done) => {
|
|
1162
|
+
chai.request(server)
|
|
1163
|
+
.get("/api/test")
|
|
1164
|
+
.auth(init.email, init.password)
|
|
1165
|
+
.end((err, res) => {
|
|
1166
|
+
res.should.have.status(200);
|
|
1167
|
+
res.headers.should.have.property("jxp-cache");
|
|
1168
|
+
res.headers["jxp-cache"].should.equal("hit");
|
|
1169
|
+
done();
|
|
1170
|
+
});
|
|
1171
|
+
});
|
|
1172
|
+
it ("should give us cache stats", (done) => {
|
|
1173
|
+
chai.request(server)
|
|
1174
|
+
.get("/cache/stats")
|
|
1175
|
+
.end((err, res) => {
|
|
1176
|
+
// console.log(res.body);
|
|
1177
|
+
res.should.have.status(200);
|
|
1178
|
+
res.body.should.have.property("hits");
|
|
1179
|
+
res.body.hits.should.equal(1);
|
|
1180
|
+
res.body.misses.should.equal(1);
|
|
1181
|
+
done();
|
|
1182
|
+
});
|
|
1183
|
+
})
|
|
1184
|
+
});
|
|
1144
1185
|
});
|