forked from Vizzuality/api-gateway
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dispatcherService.js
214 lines (186 loc) · 7.93 KB
/
dispatcherService.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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
'use strict';
var logger = require('logger');
var url = require('url');
var config = require('config');
var pathToRegexp = require('path-to-regexp');
var Service = require('models/service');
var Filter = require('models/filter');
var ServiceNotFound = require('errors/serviceNotFound');
var NotAuthorized = require('errors/notAuthorized');
var rest = require('restler');
var restCo = require('lib/restCo');
var JSONAPIDeserializer = require('jsonapi-serializer').Deserializer;
var deserializer = function(obj) {
return function(callback) {
if(obj && obj.data) {
new JSONAPIDeserializer({keyForAttribute: 'camelCase'}).deserialize(obj, callback);
} else {
callback(null, obj);
}
};
};
class DispatcherService {
static * buildUrl(sourceUrl, targetUrl, service) {
logger.debug('Building url');
var result = service.urlRegex.exec(sourceUrl);
let keys = {};
service.keys.map(function(key, i) {
keys[key] = result[i + 1];
});
let toPath = pathToRegexp.compile(targetUrl);
let buildUrl = toPath(keys);
logger.debug('Final url ' + buildUrl);
return buildUrl;
}
static * obtainFiltersAndDataProviders(url, filter) {
logger.debug('Obtaining data providers and filters ', filter);
var resultExec = filter.urlRegex.exec(url);
let keys = {};
filter.keys.map(function(key, i) {
keys[key] = resultExec[i + 1];
});
let toPath = pathToRegexp.compile(config.get('providers.' + filter.dataProvider));
let keysUrlDataset = {};
if (filter.paramProvider) {
keysUrlDataset[filter.paramProvider] = keys[filter.paramProvider];
}
let urlDataset = toPath(keys);
let requestConfig = yield DispatcherService.getRequest(urlDataset, 'GET');
logger.debug('request obtained ', requestConfig);
let request = restCo(requestConfig);
try {
let result = yield request;
if (result.response.statusCode === 200) {
logger.debug('Response 200');
let data = yield deserializer(result.body);
let filters = {};
for (let i = 0, length = filter.filters.length; i < length; i++) {
filters[filter.filters[i]] = data[filter.filters[i]];
}
let response = {
filters: filters
};
response[filter.dataProvider] = data;
return response;
}
throw new ServiceNotFound('Not found services to url:' + url);
} catch (e) {
if (e.status === 404) {
throw new ServiceNotFound('Not found services to url:' + url);
} else {
logger.error('Error to request', e);
throw e;
}
}
}
static * getRequest(sourceUrl, sourceMethod, body, headers, queryParams, files, userAuth) {
logger.debug('Obtaining config request to url %s and queryParams %s', sourceUrl, queryParams);
var parsedUrl = url.parse(sourceUrl);
logger.debug('Checking if exist in filters the url %s', sourceUrl);
let filter = yield Filter.findOne({
$where: 'this.urlRegex && this.urlRegex.test(\'' + parsedUrl.pathname + '\')',
method: sourceMethod
});
logger.debug('Filter Obtained', filter);
let dataFilters = null;
if (filter) {
try {
dataFilters = yield DispatcherService.obtainFiltersAndDataProviders(sourceUrl, filter);
} catch (e) {
logger.error('Error in obtainFiltersAndDataProviders');
if (e instanceof ServiceNotFound) {
logger.debug('Service not found');
throw e;
} else {
throw e;
}
}
logger.debug('dataFilters', dataFilters);
}
var requests = null;
let findFilters = {
$where: 'this.urlRegex && this.urlRegex.test(\'' + parsedUrl.pathname + '\')',
method: sourceMethod
};
if (dataFilters && dataFilters.filters) {
findFilters.filters = dataFilters.filters;
}
var service = yield Service.findOne(findFilters);
logger.debug('Service obtained: ', service);
let configRequest = null;
if (service) {
logger.info('Checking if the request is authenticated');
if (service.authenticated && !userAuth) {
throw new NotAuthorized(sourceUrl + ': login required');
}
}
if (service && service.endpoint) {
let endpoint = service.endpoint;
logger.debug('Endpoint', endpoint);
logger.info('Dispathing request from %s to %s%s private endpoint. Type: %s', parsedUrl.pathname, endpoint.baseUrl, endpoint.path, endpoint.type);
let url = yield DispatcherService.buildUrl(parsedUrl.pathname, endpoint.path, service);
configRequest = {
uri: endpoint.baseUrl + url,
method: endpoint.method,
binary: service.binary
};
if (queryParams) {
configRequest.uri = configRequest.uri + queryParams;
}
logger.debug('Create request to %s', configRequest.uri);
if (endpoint.method === 'POST' || endpoint.method === 'PATCH' || endpoint.method === 'PUT') {
logger.debug('Method is %s. Adding body', configRequest.method);
configRequest.data = body;
}
if (files) {
logger.debug('Adding files');
let formData = {};
for (let key in files) {
formData[key] = rest.file(files[key].path);
}
configRequest.data = Object.assign(configRequest.data || {}, formData);
configRequest.multipart = true;
}
if (headers) {
config.headers = headers;
}
if (endpoint.data) {
logger.debug('Obtaining data to endpoints');
for (let k = 0, lengthData = endpoint.data.length; k < lengthData; k++) {
if (endpoint.data[k] === 'loggedUser') {
configRequest.data[endpoint.data[k]] = userAuth;
if (!userAuth) {
logger.warn('User not logged. Add undefined in userLogged body parameter');
}
} else {
if (!dataFilters || !dataFilters[endpoint.data[k]]) {
//TODO obtain data
}
if (dataFilters) {
configRequest.data[endpoint.data[k]] = dataFilters[endpoint.data[k]];
}
}
}
logger.debug('Final request', configRequest);
}
//if is authenticated add user in the body
var methodsWithBody = ['POST', 'PATCH', 'PUT'];
logger.info('user auth', userAuth);
if (userAuth !== undefined) {
if (methodsWithBody.indexOf(endpoint.method) > -1) {
logger.debug('Adding user in the body because url is authenticated');
configRequest.data.loggedUser = userAuth;
} else {
logger.debug('Adding user in the query string because url is authenticated');
configRequest.query = configRequest.query || {};
configRequest.query.loggedUser = userAuth;
}
}
return configRequest;
} else {
logger.error('Endpoint not found');
throw new ServiceNotFound('Not found services to url:' + sourceUrl);
}
}
}
module.exports = DispatcherService;