1 | import { register, injectWithName } from "./global-injector";
|
2 | import { ParsedAny, Parser } from "./parser";
|
3 | import { each, map, grep } from "./each";
|
4 | import { extend, module } from "./helpers";
|
5 | import { service } from "./service";
|
6 | import { FormatterFactory } from "./formatters/common";
|
7 | import * as uri from 'url';
|
8 | import * as qs from 'querystring'
|
9 | import 'isomorphic-fetch';
|
10 | import { Injected } from "./injector";
|
11 |
|
12 | export interface HttpOptions
|
13 | {
|
14 | method?: string;
|
15 | url: string | uri.UrlObject;
|
16 | queryString?: any;
|
17 | body?: any;
|
18 | headers?: { [key: string]: string | number | Date };
|
19 | contentType?: 'json' | 'form';
|
20 | type?: 'json' | 'xml' | 'text' | 'raw';
|
21 | }
|
22 |
|
23 | export interface Http<TResponse = Response>
|
24 | {
|
25 | get(url: string, params?: any): PromiseLike<TResponse>;
|
26 | post(url: string, body?: any): PromiseLike<FormData>;
|
27 | postJSON<T = string>(url: string, body?: any): PromiseLike<T>;
|
28 | getJSON<T>(url: string, params?: any): PromiseLike<T>;
|
29 | invokeSOAP(namespace: string, action: string, url: string, params?: { [key: string]: string | number | boolean }): PromiseLike<TResponse>;
|
30 | call(options: HttpOptions): PromiseLike<TResponse>;
|
31 | }
|
32 |
|
33 | @service('$http')
|
34 | export class FetchHttp implements Http<Response>
|
35 | {
|
36 | constructor()
|
37 | {
|
38 | }
|
39 |
|
40 | public get(url: string, params?: any)
|
41 | {
|
42 | return this.call({ url: url, method: 'GET', queryString: params });
|
43 | }
|
44 | public post(url: string, body?: any): PromiseLike<FormData>
|
45 | {
|
46 | return this.call({ method: 'POST', url: url, body: body }).then((r) =>
|
47 | {
|
48 | return r.formData();
|
49 | });
|
50 | }
|
51 | public postJSON<T = string>(url: string, body?: any): PromiseLike<T>
|
52 | {
|
53 | return this.call({ method: 'POST', url: url, body: body, contentType: 'json', type: 'json' }).then((r) =>
|
54 | {
|
55 | return r.json();
|
56 | });
|
57 | }
|
58 | public getJSON<T>(url: string, params?: any): PromiseLike<T>
|
59 | {
|
60 | return this.call({ method: 'GET', url: url, queryString: params, type: 'json' }).then((r) =>
|
61 | {
|
62 | return r.json();
|
63 | });
|
64 | }
|
65 |
|
66 | public invokeSOAP(namespace: string, action: string, url: string, params?: { [key: string]: string | number | boolean })
|
67 | {
|
68 | var body = '<?xml version="1.0" encoding="utf-8"?><s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body>' +
|
69 | '<u:' + action + ' xmlns:u="' + namespace + '">';
|
70 | each(params, function (paramValue, paramName)
|
71 | {
|
72 | body += '<' + paramName + '><![CDATA[' + paramValue + ']]></' + paramName + '>';
|
73 | });
|
74 | body += '</u:' + action + '></s:Body></s:Envelope>';
|
75 | return this.call({ method: 'POST', url: url, type: 'xml', headers: { SOAPAction: namespace + '#' + action }, body: body });
|
76 | }
|
77 |
|
78 | public call(options: HttpOptions): Promise<Response>
|
79 | {
|
80 | var init: RequestInit = { method: options.method || 'GET', body: options.body };
|
81 | if (typeof (options.url) == 'string')
|
82 | options.url = uri.parse(options.url, true);
|
83 | if (options.queryString)
|
84 | {
|
85 | if (typeof (options.queryString) == 'string')
|
86 | options.queryString = qs.parse(options.queryString);
|
87 | options.url.query = extend(options.url.query, options.queryString);
|
88 | }
|
89 |
|
90 | if (options.headers)
|
91 | {
|
92 | init.headers = {};
|
93 | each(options.headers, function (value, key)
|
94 | {
|
95 | if (value instanceof Date)
|
96 | init.headers[key as string] = value.toJSON();
|
97 | else
|
98 | init.headers[key as string] = value && value.toString();
|
99 | });
|
100 | }
|
101 |
|
102 | if (options.type)
|
103 | {
|
104 | init.headers = init.headers || {};
|
105 | switch (options.type)
|
106 | {
|
107 | case 'json':
|
108 | init.headers['Accept'] = 'application/json, text/json';
|
109 | if (!options.contentType && typeof (init.body) !== 'string')
|
110 | init.body = JSON.stringify(init.body);
|
111 | break;
|
112 | case 'xml':
|
113 | init.headers['Accept'] = 'text/xml';
|
114 | break;
|
115 | case 'text':
|
116 | init.headers['Accept'] = 'text/plain';
|
117 | break;
|
118 | }
|
119 | }
|
120 |
|
121 | if (options.contentType && options.body)
|
122 | {
|
123 | init.headers = init.headers || {};
|
124 | switch (options.contentType)
|
125 | {
|
126 | case 'json':
|
127 | init.headers['Content-Type'] = 'application/json; charset=UTF-8'
|
128 | if (typeof (init.body) !== 'string')
|
129 | init.body = JSON.stringify(init.body);
|
130 | break;
|
131 | case 'form':
|
132 | init.headers['Content-Type'] = 'multipart/form-data';
|
133 | if (!(init.body instanceof FormData) && typeof init.body == 'undefined')
|
134 | init.body = FetchHttp.serialize(init.body);
|
135 | break;
|
136 | }
|
137 | }
|
138 |
|
139 | return fetch(uri.format(options.url), init);
|
140 | }
|
141 |
|
142 |
|
143 | public static serialize(obj, prefix?: string)
|
144 | {
|
145 | return map(obj, function (value, key: string)
|
146 | {
|
147 |
|
148 | if (typeof (value) == 'object')
|
149 | {
|
150 |
|
151 | var keyPrefix = prefix;
|
152 | if (prefix)
|
153 | {
|
154 | if (typeof (key) == 'number')
|
155 | keyPrefix = prefix.substring(0, prefix.length - 1) + '[' + key + '].';
|
156 | else
|
157 | keyPrefix = prefix + encodeURIComponent(key) + '.';
|
158 | }
|
159 | return FetchHttp.serialize(value, keyPrefix);
|
160 | }
|
161 | else
|
162 | {
|
163 | return (prefix || '') + encodeURIComponent(key) + '=' + encodeURIComponent(value);
|
164 | }
|
165 | }, true)
|
166 | }
|
167 |
|
168 | }
|
169 |
|
170 |
|
171 |
|
172 | export class HttpCallFormatterFactory implements FormatterFactory<() => Promise<any>, { method?: keyof Http }>
|
173 | {
|
174 | constructor() { }
|
175 | public parse(expression: string): { method?: keyof Http } & ParsedAny
|
176 | {
|
177 | var method = /^ *(\w+)/.exec(expression);
|
178 | if (method)
|
179 | return { method: <keyof Http>method[1], $$length: method[0].length };
|
180 | return Parser.parseAny(expression, false);
|
181 | }
|
182 | public build(formatter, settings: { method: keyof Http }): Injected<any>
|
183 | {
|
184 | if (!settings)
|
185 | settings = { method: 'getJSON' };
|
186 |
|
187 | return function (scope)
|
188 | {
|
189 | var settingsValue = settings as HttpOptions & { method?: keyof Http };
|
190 | if (settings instanceof Function)
|
191 | settingsValue = settings(scope);
|
192 |
|
193 | return injectWithName(['$http'], function (http: Http)
|
194 | {
|
195 | var formattedValue = formatter(scope);
|
196 | if (typeof (formattedValue) == 'string')
|
197 | return (http[settingsValue.method || 'getJSON'] as Function)(formattedValue, grep(settingsValue, function (value, key)
|
198 | {
|
199 | return key != 'method';
|
200 | }));
|
201 |
|
202 | if (Array.isArray(formattedValue))
|
203 | {
|
204 | return (http[settingsValue.method || 'getJSON'] as Function).apply(http, formattedValue);
|
205 | }
|
206 |
|
207 | return (http[settingsValue.method || 'getJSON'] as Function)(formattedValue);
|
208 | });
|
209 | }
|
210 | }
|
211 | }
|
212 |
|
213 | export class HttpFormatterFactory extends HttpCallFormatterFactory implements FormatterFactory<Promise<any>, { method?: keyof Http }>
|
214 | {
|
215 | constructor()
|
216 | {
|
217 | super();
|
218 | }
|
219 |
|
220 | public build(formatter, settings: { method: keyof Http })
|
221 | {
|
222 | return (value) =>
|
223 | {
|
224 | return super.build(formatter, settings)(value)();
|
225 | };
|
226 | }
|
227 | }
|
228 |
|
229 | module('$formatters').register('#http', new HttpFormatterFactory());
|
230 | module('$formatters').register('#httpCall', new HttpCallFormatterFactory()); |
\ | No newline at end of file |