UNPKG

8.04 kBPlain TextView Raw
1import { register, injectWithName } from "./global-injector";
2import { ParsedAny, Parser } from "./parser";
3import { each, map, grep } from "./each";
4import { extend, module } from "./helpers";
5import { service } from "./service";
6import { FormatterFactory } from "./formatters/common";
7import * as uri from 'url';
8import * as qs from 'querystring'
9import 'isomorphic-fetch';
10import { Injected } from "./injector";
11
12export 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
23export 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')
34export 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
172export 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
213export 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
229module('$formatters').register('#http', new HttpFormatterFactory());
230module('$formatters').register('#httpCall', new HttpCallFormatterFactory());
\No newline at end of file