1 | import { Subject } from 'rxjs/Subject';
|
2 | import 'rxjs/add/operator/map';
|
3 | import 'rxjs/add/operator/takeUntil';
|
4 | import 'rxjs/add/operator/take';
|
5 | import 'rxjs/add/operator/toPromise';
|
6 | import { Log, Level } from 'ng2-logger/browser';
|
7 | const log = Log.create('resouce-service', Level.__NOTHING);
|
8 | import { Rest } from './rest.class';
|
9 | import { RestRequest } from './rest-request';
|
10 | import { RestHeaders } from './rest-headers';
|
11 | import { Cookie } from './cookie';
|
12 | import { interpolateParamsToUrl, isValid, containsModels, getModels } from './params';
|
13 |
|
14 | export class Resource {
|
15 |
|
16 |
|
17 | constructor() {
|
18 | setTimeout(() => {
|
19 | const zone = this.getZone();
|
20 | if (!RestRequest.zone)
|
21 | RestRequest.zone = zone;
|
22 | });
|
23 | }
|
24 | static get listenErrors() {
|
25 | return this._listenErrors.asObservable();
|
26 | }
|
27 |
|
28 | getZone() {
|
29 | const isNode = (typeof window === 'undefined');
|
30 | if (isNode)
|
31 | return;
|
32 | const ng = window['ng'];
|
33 | const getAllAngularRootElements = window['getAllAngularRootElements'];
|
34 | if (!ng || !getAllAngularRootElements)
|
35 | return;
|
36 | const probe = ng.probe;
|
37 | const coreTokens = ng.coreTokens;
|
38 | if (!coreTokens.NgZone)
|
39 | return;
|
40 | const zoneClass = coreTokens.NgZone;
|
41 | if (!probe || typeof probe !== 'function' || !getAllAngularRootElements)
|
42 | return;
|
43 | const angularElements = getAllAngularRootElements();
|
44 | if (!Array.isArray(angularElements) || angularElements.length === 0)
|
45 | return;
|
46 | const rootElement = ng.probe(angularElements[0]);
|
47 | if (!rootElement)
|
48 | return;
|
49 | const injector = rootElement.injector;
|
50 | if (!injector || !injector.get || typeof injector.get !== 'function')
|
51 | return;
|
52 | const zone = injector.get(zoneClass);
|
53 | return zone;
|
54 | }
|
55 | static initAngularNgZone(zone) {
|
56 | RestRequest.zone = zone;
|
57 | }
|
58 | checkNestedModels(model, allModels) {
|
59 |
|
60 | for (let p in allModels) {
|
61 | if (allModels.hasOwnProperty(p)) {
|
62 | let m = allModels[p];
|
63 | if (isValid(p)) {
|
64 | let urlModels = getModels(p);
|
65 | if (containsModels(model, urlModels)) {
|
66 | model = p;
|
67 | break;
|
68 | }
|
69 | }
|
70 | }
|
71 | }
|
72 |
|
73 | return model;
|
74 | }
|
75 | static getModel(endpoint, model) {
|
76 | model = Resource.prepareModel(model);
|
77 | const e = Resource.endpoints[endpoint];
|
78 | if (!e)
|
79 | return undefined;
|
80 | const r = Resource.endpoints[endpoint].models[model];
|
81 | return Resource.endpoints[endpoint].models[model];
|
82 | }
|
83 |
|
84 |
|
85 | static create(e, model, entityMapping, circular) {
|
86 | const badRestRegEX = new RegExp('((\/:)[a-z]+)+', 'g');
|
87 | const matchArr = model.match(badRestRegEX) || [];
|
88 | const badModelsNextToEachOther = matchArr.join();
|
89 | const atleas2DoubleDots = ((badModelsNextToEachOther.match(new RegExp(':', 'g')) || []).length >= 2);
|
90 | if (atleas2DoubleDots && model.search(badModelsNextToEachOther) !== -1) {
|
91 | throw new Error(`
|
92 |
|
93 | Bad rest model: ${model}
|
94 |
|
95 | Do not create rest models like this: /book/author/:bookid/:authorid
|
96 | Instead use nested approach: /book/:bookid/author/:authorid
|
97 | `);
|
98 | }
|
99 | ;
|
100 | Resource.map(e, e);
|
101 | Resource.instance.add(e, model ? model : '', entityMapping, circular);
|
102 |
|
103 | return {
|
104 | model: (params) => Resource.instance.api(e, interpolateParamsToUrl(params, model)),
|
105 | replay: (method) => {
|
106 | Resource.getModel(e, model).replay(method);
|
107 | },
|
108 | get headers() {
|
109 | return Resource.getModel(e, model).headers;
|
110 | }
|
111 | };
|
112 | }
|
113 |
|
114 |
|
115 | static reset() {
|
116 | Resource.endpoints = {};
|
117 | }
|
118 |
|
119 | static map(endpoint, url) {
|
120 | log.i('url', url);
|
121 | let regex = /(http|https):\/\/(\w+:{0,1}\w*)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%!\-\/]))?/;
|
122 | let e = endpoint;
|
123 | if (!regex.test(url)) {
|
124 | throw `Url address is not correct: ${url}`;
|
125 | }
|
126 | if (url.charAt(url.length - 1) === '/')
|
127 | url = url.slice(0, url.length - 1);
|
128 | log.i('url after', url);
|
129 | if (Resource.endpoints[e] !== undefined) {
|
130 | if (Resource.enableWarnings)
|
131 | console.warn('Cannot use map function at the same API endpoint again ('
|
132 | + Resource.endpoints[e].url + ')');
|
133 | return false;
|
134 | }
|
135 | Resource.endpoints[e] = {
|
136 | url: url,
|
137 | models: {},
|
138 | entity: null
|
139 | };
|
140 | log.i('enpoints', Resource.endpoints);
|
141 | return true;
|
142 | }
|
143 |
|
144 | static prepareModel(model) {
|
145 | if (model.charAt(model.length - 1) === '/')
|
146 | model = model.slice(0, model.length - 1);
|
147 | if (model.charAt(0) === '/')
|
148 | model = model.slice(1, model.length);
|
149 | return model;
|
150 | }
|
151 |
|
152 | |
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 |
|
159 | add(endpoint, model, entity, circular) {
|
160 | log.i(`I am maping ${model} on ${endpoint}`);
|
161 | model = Resource.prepareModel(model);
|
162 | let e;
|
163 | e = (endpoint).toString();
|
164 | if (Resource.endpoints[e] === undefined) {
|
165 | console.error('Endpoint is not mapped ! Cannot add model ' + model);
|
166 | return;
|
167 | }
|
168 | if (Resource.endpoints[e].models[model] !== undefined) {
|
169 | if (Resource.enableWarnings)
|
170 | console.warn(`Model '${model}' is already defined in endpoint: `
|
171 | + Resource.endpoints[e].url);
|
172 | return;
|
173 | }
|
174 | Resource.endpoints[e].models[model] =
|
175 | new Rest(Resource.endpoints[e].url
|
176 | + '/' + model, Resource.request, {
|
177 | endpoint: e,
|
178 | path: model,
|
179 | entity,
|
180 | circular
|
181 | });
|
182 | return;
|
183 | }
|
184 |
|
185 |
|
186 | |
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 | api(endpoint, model) {
|
194 | if (model.charAt(0) === '/')
|
195 | model = model.slice(1, model.length);
|
196 | let e = (endpoint).toString();
|
197 | if (Resource.endpoints[e] === undefined) {
|
198 | throw `Endpoint: ${endpoint} is not mapped ! Cannot add model: ${model}`;
|
199 | }
|
200 | let allModels = Resource.endpoints[e].models;
|
201 | let orgModel = model;
|
202 | model = this.checkNestedModels(model, allModels);
|
203 | if (Resource.endpoints[e].models[model] === undefined) {
|
204 | log.d('Resource.endpoints', Resource.endpoints);
|
205 | throw `Model '${model}' is undefined in endpoint: ${Resource.endpoints[e].url} `;
|
206 | }
|
207 | let res = Resource.endpoints[(endpoint).toString()].models[model];
|
208 | if (orgModel !== model) {
|
209 | let baseUrl = Resource.endpoints[(endpoint).toString()].url;
|
210 | log.d('base', Resource.endpoints[(endpoint).toString()]);
|
211 | log.d('baseUrl', baseUrl);
|
212 | log.d('orgModel', orgModel);
|
213 | res.__rest_endpoint = `${baseUrl}/${orgModel}`;
|
214 | }
|
215 | else
|
216 | res.__rest_endpoint = undefined;
|
217 | return res;
|
218 | }
|
219 | }
|
220 | Resource.DEFAULT_HEADERS = RestHeaders.from({
|
221 | 'Content-Type': 'application/json',
|
222 | 'Accept': 'application/json'
|
223 | });
|
224 | Resource._listenErrors = new Subject();
|
225 | Resource.enableWarnings = true;
|
226 | Resource.instance = new Resource();
|
227 | Resource.endpoints = {};
|
228 | Resource.request = new RestRequest();
|
229 |
|
230 | Resource.Cookies = Cookie.Instance;
|
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
\ | No newline at end of file |