-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
143 lines (131 loc) · 5.46 KB
/
index.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
const fs = require('fs');
const util = require('./util');
const http = require('http');
const https = require('https');
const querystring = require('querystring');
class Client {
constructor(routes) {
if(!routes) {
throw new Error("Routes config is required");
}
if(typeof routes == 'string') {
try {
routes = JSON.parse(routes);
}
catch(e) {
throw new Error("Error parsing config file", e);
}
}
this.routes = routes;
this.setupRoutes();
}
setupRoutes() {
let routes = this.routes;
this.generateApi(routes.api);
}
generateApi(routes, histRoutes = "") {
let self = this;
let parts = histRoutes.split('/');
// Nested API, we need up update self to point last object
if(parts.length > 1) {
for(let i = 1; i < parts.length; i++) {
self = self[util.toCamelCase(parts[i])];
}
}
Object.keys(routes).forEach((key) => {
// Key name will become the intermediate method
// for all the endpoints
let sub = routes[key];
let curRoute = histRoutes + '/' + key;
let cur = util.toCamelCase(key);
if(sub.url) {
// Consider end of recursion when url is present in sub
self[cur] = (obj) => {
return new Promise((resolve, reject) => {
try {
let body = this.validateParams(obj, sub.params);
let options = {
host: this.routes.defines.constants.host,
port: this.routes.defines.constants.port,
path: sub.url,
method: sub.method,
headers: {
'content-type': sub.contentType || 'application/json'
}
};
// Sets the query parameters on get request
if(options.method === 'GET') {
options.path += '?' + querystring.stringify(body);
}
// User https if api is hosted on https
let transport = (options.port === 443) ? https: http;
let req = transport.request(options, (res) => {
res.setEncoding("utf8");
let data = "";
res.on("data", function(chunk) {
data += chunk;
});
res.on("error", function(err) {
console.log('Error occured in http request', err);
});
res.on("end", function() {
console.log('Request ended');
if (res.statusCode >= 400 && res.statusCode < 600 || res.statusCode < 10) {
reject(new Error(data));
} else {
if(res.headers['content-type'].indexOf('application/json') !== -1) {
try {
res.data = JSON.parse(data);
}
catch(e) {
reject(e);
}
}
else
res.data = data;
resolve(res);
}
});
});
let hasBody ='get|delete|head'.indexOf(sub.method.toLowerCase()) === -1;
if(hasBody) {
console.log('writing to request, ', JSON.stringify(body));
req.write(JSON.stringify(body));
}
req.end();
}
catch(e){
reject(e);
}
});
};
}
else {
// Dig deeper (recursion)
if(cur.length)
self[cur] = {};
this.generateApi(routes[key], curRoute);
}
});
}
validateParams(obj, paramsList) {
// Validates provided parameters with that of
// required parameters for request
let params = Object.keys(paramsList);
for( let parameter of params) {
let def = this.routes.defines.params[parameter];
let val = obj[parameter];
if(val) {
if(typeof val != def.type.toLowerCase())
throw new Error(parameter + " value incompatible");
}
else if(def.required) {
throw new Error(parameter + " is required");
}
}
return obj;
}
}
module.exports = (config) => {
return new Client(config);
};