1 | # HttpClient.js
|
2 |
|
3 | HttpClient.js is a library that aims to make it easier to send data to the server and to parse the data returned by the
|
4 | server in the browsers. It provides both Promise-style and Callback-style API and can be used to send http requests or
|
5 | JSONP requests. It is highly configurable which make it very easy to extend the functionality of this library.
|
6 |
|
7 | ## Features
|
8 |
|
9 | * Path variables compilation.
|
10 | * Query string compilation.
|
11 | * Request body processing (JSON, Form, Raw).
|
12 | * Response content processing.
|
13 | * Http requests and JSONP requests.
|
14 | * Timeout and request cancellation.
|
15 | * Promise-style and Callback-style API.
|
16 |
|
17 | ## Contents
|
18 |
|
19 | * [HttpClient.js](#httpclientjs)
|
20 | * [Features](#features)
|
21 | * [Contents](#contents)
|
22 | * [Getting Started](#getting-started)
|
23 | * [1. Creating HttpClient instance](#1-creating-httpclient-instance)
|
24 | * [2. Sending HTTP requests](#2-sending-http-requests)
|
25 | * [3. Sending JSONP requests](#3-sending-jsonp-requests)
|
26 | * [4. Using Promise](#4-using-promise)
|
27 | * [Classes](#classes)
|
28 | * [HttpClient](#httpclient)
|
29 | * [Default Request Options](#default-request-options)
|
30 |
|
31 | ## Getting Started
|
32 |
|
33 | ### 1. Creating HttpClient instance
|
34 |
|
35 | Sending requests with HttpClient.js is really easy. The first thing we should do is to create an instance of
|
36 | `HttpClient`. When using HttpClient.js, the best practice is to save the configured `HttpClient` instance in
|
37 | a single module, and reuse that instance many times.
|
38 |
|
39 | ```js
|
40 | var HttpClient = require('x-http-client');
|
41 | var client = new HttpClient({
|
42 | baseURL: 'https://api.example.com',
|
43 | });
|
44 | ```
|
45 |
|
46 | The signature of this `HttpClient` constructor is:
|
47 |
|
48 | ```js
|
49 | /**
|
50 | * @class
|
51 | * @param {RequestOptions} [defaultOptions] The default request options.
|
52 | * @param {HandleOptionsFunction} [handleOptions] The function to handle the mereged default options.
|
53 | */
|
54 | HttpClient([defaultOptions, [handleOptions]]);
|
55 | ```
|
56 |
|
57 | ### 2. Sending HTTP requests
|
58 |
|
59 | After creating the `HttpClient` instance, now we can use that instance to send http requests. In the following example,
|
60 | we are going to send an HTTP `PUT` request to the server.
|
61 |
|
62 | ```js
|
63 | /**
|
64 | * @type {HttpRequest} The return value of `send(...)` is an instance of `HttpRequest`.
|
65 | */
|
66 | var request = client.send({
|
67 | // PUT https://api.example.com/posts/1?category=javascript
|
68 | method: 'PUT',
|
69 | url: '/posts/{postId}',
|
70 | param: {
|
71 | postId: 1
|
72 | },
|
73 | query: {
|
74 | category: 'javascript'
|
75 | },
|
76 | headers: {
|
77 | 'X-My-Custom-Header': 'header-value'
|
78 | },
|
79 | body: {
|
80 | // The property name `json` here tells the library that the type
|
81 | // of the data we are going to send to the server is JSON.
|
82 | // That means we should use `JSON.stringify(data)` to encode the
|
83 | // data before sending it to the server, and set the request
|
84 | // header `Content-Type` to `application/json; charset=UTF-8`.
|
85 | // The library will use the name `json` to find a request content
|
86 | // processor in the `options.httpRequestBodyProcessor` and use
|
87 | // that processor to process the data and set request headers.
|
88 | // The library provides three processor. They are `json`, `form`
|
89 | // and `raw`. You can rewrite them, delete them or add a new one
|
90 | // by merge your options to the default options.
|
91 | json: {
|
92 | title: 'Introducing HttpClient.js',
|
93 | content: 'The content of the post...'
|
94 | }
|
95 | }
|
96 | }, function (response) {
|
97 | var data = response.json();
|
98 | console.log(data);
|
99 | }, function (error) {
|
100 | console.log(error.message);
|
101 | });
|
102 | ```
|
103 |
|
104 | ### 3. Sending JSONP requests
|
105 |
|
106 | You can also use HttpClient instance to send a JSONP request.
|
107 |
|
108 | ```js
|
109 | /**
|
110 | * @type {JSONPRequest} The return value of `getJSONP(...)` is an instance of `JSONPRequest`.
|
111 | */
|
112 | var request = client.getJSONP({
|
113 | url: '/dictionary/search',
|
114 | query: {
|
115 | word: 'javascript'
|
116 | },
|
117 | timeout: 6000
|
118 | }, function (response) {
|
119 | var data = response.json();
|
120 | console.log(data);
|
121 | }, function (error) {
|
122 | console.log(error.message);
|
123 | });
|
124 | ```
|
125 |
|
126 | ### 4. Using Promise
|
127 |
|
128 | If you prefer the Promise-style API, just change the method name from `send` to `fetch`, `getJSONP` to `fetchJSONP`.
|
129 |
|
130 | ```js
|
131 | // Sending HTTP request with Promise-style API:
|
132 | client.fetch({
|
133 | // PUT https://api.example.com/posts/1?category=javascript
|
134 | method: 'PUT',
|
135 | url: '/posts/{postId}',
|
136 | param: {
|
137 | postId: 1
|
138 | },
|
139 | query: {
|
140 | category: 'javascript'
|
141 | },
|
142 | headers: {
|
143 | 'X-My-Custom-Header': 'header-value'
|
144 | },
|
145 | body: {
|
146 | json: {
|
147 | title: 'Introducing HttpClient.js',
|
148 | content: 'The content of the post...'
|
149 | }
|
150 | }
|
151 | }).then(function (response) {
|
152 | var data = response.json();
|
153 | console.log(data);
|
154 | }).catch(function (error) {
|
155 | console.log(error.message);
|
156 | });
|
157 |
|
158 | // Sending JSONP request with Promise-style API:
|
159 | client.fetchJSONP({
|
160 | url: '/dictionary/search',
|
161 | query: {
|
162 | word: 'javascript'
|
163 | },
|
164 | timeout: 6000
|
165 | }).then(function (response) {
|
166 | var data = response.json();
|
167 | console.log(data);
|
168 | }).catch(function (error) {
|
169 | console.log(error.message);
|
170 | });
|
171 | ```
|
172 |
|
173 | ## Default Request Options
|
174 |
|
175 | ```js
|
176 | {
|
177 | // The http request method. The default method is `GET`.
|
178 | method: 'GET',
|
179 |
|
180 | // The request base url. If the `url` is relative url, and the `baseURL` is not `null`,
|
181 | // the `baseURL` will be prepend to the `url`.
|
182 | baseURL: null,
|
183 |
|
184 | // The request url that can contain any number of placeholders, and will be compiled with
|
185 | // the data that passed in with `options.param`.
|
186 | url: null,
|
187 |
|
188 | // The data used to compile the request url.
|
189 | param: null,
|
190 |
|
191 | // The data that will be compiled to query string.
|
192 | query: null,
|
193 |
|
194 | // The object that contains the headers to set when sending the request.
|
195 | // Only the non-undefined and non-null headers are set.
|
196 | headers: null,
|
197 |
|
198 | // The object that contains the content which will be send to the server. This object
|
199 | // has only one property. The name of the property is the content type of the content,
|
200 | // which will be used to find a processor in `options.httpRequestBodyProcessor`.
|
201 | // The processor is used to process the value of the property. The processed value
|
202 | // which the processor returns will be send to the server as the request body.
|
203 | body: null,
|
204 |
|
205 | // The object to keep the extra information that the user passed in. The library itself
|
206 | // will not touch this property. You can use this property to hold any information that
|
207 | // you want, when you extend the functionality of your own instance of `HttpClient`.
|
208 | // The default value of this property is an empty object.
|
209 | extra: {},
|
210 |
|
211 | // The `CancelController` used to cancel the request. It only works when using `fetch`
|
212 | // or `fetchJSONP` to send request. If the you send request using `send` or `getJSONP`,
|
213 | // the `options.controller` will be set to `null`.
|
214 | controller: null,
|
215 |
|
216 | // The name of the function that send the request. Can be `send`, `fetch`, `getJSONP`,
|
217 | // `fetchJSONP`. This value is set by the library, don't change it.
|
218 | requestFunctionName: null,
|
219 |
|
220 | // The request type of this request. The value of it is set by the library itself,
|
221 | // can be `HTTP_REQUEST` or `JSONP_REQUEST`. Any other value the user passed in is
|
222 | // ignored. You can use this property to get the type of the current request.
|
223 | requestType: null,
|
224 |
|
225 | // Whether to set `withCredentials` property of the `XMLHttpRequest` to `true`.
|
226 | // The default value is `false`.
|
227 | cors: false,
|
228 |
|
229 | // The object that contains the properties to set on the instance of the `XMLHttpRequest`.
|
230 | xhrProps: null,
|
231 |
|
232 | // The user name to use for authentication purposes. The defualt value is `null`.
|
233 | username: null,
|
234 |
|
235 | // The password to use for authentication purposes. The defualt value is `null`.
|
236 | password: null,
|
237 |
|
238 | // The number of milliseconds the request can take before it finished. If the timeout
|
239 | // value is `0`, no timer will be set. If the request does not finsihed within the given
|
240 | // time, a timeout error will be thrown. The default value is `0`.
|
241 | timeout: 0,
|
242 |
|
243 | // Whether to disable the cache. If the value is `true`, the headers in
|
244 | // `options.noCacheHeaders` will be set. The default value is `false`.
|
245 | noCache: false,
|
246 |
|
247 | // The headers to set when `options.noCache` is set to `true`.
|
248 | noCacheHeaders: {
|
249 | 'Pragma': 'no-cache',
|
250 | 'Cache-Control': 'no-cache, no-store, must-revalidate'
|
251 | },
|
252 |
|
253 | // The query string key to hold the value of the callback name when sending JSONP request.
|
254 | // The default values is `callback`.
|
255 | jsonp: 'callback',
|
256 |
|
257 | // The object to config the error messages. The keys in the object are error code
|
258 | // such as `ERR_NETWORK`.
|
259 | errorMessages: {
|
260 | ERR_ABORTED: 'Request aborted',
|
261 | ERR_CANCELLED: 'Request cancelled',
|
262 | ERR_NETWORK: 'Network error',
|
263 | ERR_RESPONSE: 'Response error',
|
264 | ERR_TIMEOUT: 'Request timeout'
|
265 | },
|
266 |
|
267 | // The object that contains the http request body processors.
|
268 | httpRequestBodyProcessor: {
|
269 | raw: {
|
270 | priority: 0,
|
271 | headers: null,
|
272 | processor: null,
|
273 | },
|
274 | form: {
|
275 | priority: 1,
|
276 | headers: {
|
277 | 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
|
278 | },
|
279 | processor: function (data, options) {
|
280 | return QS.encode(data);
|
281 | }
|
282 | },
|
283 | json: {
|
284 | priority: 2,
|
285 | headers: {
|
286 | 'Content-Type': 'application/json; charset=UTF-8'
|
287 | },
|
288 | processor: function (data, options) {
|
289 | return JSON.stringify(data);
|
290 | }
|
291 | }
|
292 | },
|
293 |
|
294 | // The object that contains the http response parsers.
|
295 | httpResponseParser: {
|
296 | json: function () {
|
297 | // `this` is point to the current instance of `HttpResponse`.
|
298 | var responseText = this.request.xhr.responseText;
|
299 | return responseText ? JSON.parse(responseText) : null;
|
300 | },
|
301 | text: function () {
|
302 | return this.request.xhr.responseText;
|
303 | },
|
304 | status: function () {
|
305 | return this.request.xhr.status;
|
306 | }
|
307 | },
|
308 |
|
309 | // The object that contains the jsonp response parsers.
|
310 | jsonpResponseParser: {
|
311 | json: function () {
|
312 | return this.request.jsonpResponseJSON;
|
313 | }
|
314 | },
|
315 |
|
316 | // The object that contains the http response error parsers.
|
317 | httpResponseErrorParser: null,
|
318 |
|
319 | // The object that contains the jsonp response error parsers.
|
320 | jsonpResponseErrorParser: null,
|
321 |
|
322 | // The function to handle the options.
|
323 | handleOptions: null,
|
324 |
|
325 | // The function to create the `XMLHttpRequest` instance.
|
326 | createXHR: function (options) {
|
327 | return new XMLHttpRequest();
|
328 | },
|
329 |
|
330 | // The function to create the `HTMLScriptElement` instance.
|
331 | createScript: function (options) {
|
332 | var script = document.createElement('script');
|
333 |
|
334 | script.setAttribute('type', 'text/javascript');
|
335 | script.setAttribute('charset', 'utf-8');
|
336 |
|
337 | return script;
|
338 | },
|
339 |
|
340 | // The function that returns the container node, which will be used to append the
|
341 | // script element when sending jsonp request.
|
342 | jsonpContainerNode: function (options) {
|
343 | return document.head || document.getElementsByName('head')[0];
|
344 | },
|
345 |
|
346 | // The function to generate the unique callback name when sending jsonp request.
|
347 | jsonpCallbackName: function (options) {
|
348 | return 'jsonp_' + uuid() + '_' + (new Date().getTime());
|
349 | },
|
350 |
|
351 | // The function to compile url.
|
352 | compileURL: function (url, param, options) {
|
353 | return template(url, param);
|
354 | },
|
355 |
|
356 | // The function to encode the query string.
|
357 | encodeQueryString: function (data, options) {
|
358 | return QS.encode(data);
|
359 | },
|
360 |
|
361 | // The function to call on xhr created.
|
362 | onXhrCreated: null,
|
363 |
|
364 | // The functon to call on xhr opened.
|
365 | onXhrOpened: null,
|
366 |
|
367 | // The function to call on xhr sent.
|
368 | onXhrSent: null,
|
369 |
|
370 | // The function to call on request created.
|
371 | onRequestCreated: null,
|
372 |
|
373 | // The function to check whether the response is ok.
|
374 | isResponseOk: function (requestType, response) {
|
375 | var status;
|
376 |
|
377 | // Http reqest
|
378 | if (requestType === HTTP_REQUEST) {
|
379 | status = response.request.xhr.status;
|
380 | return (status >= 200 && status < 300) || status === 304;
|
381 | }
|
382 |
|
383 | // JSONP request
|
384 | return true;
|
385 | },
|
386 |
|
387 | // The function to transfrom the response error.
|
388 | // The return value of this function will be passed to the `onerror` callback.
|
389 | transformError: null,
|
390 |
|
391 | // The function to transfrom the response.
|
392 | // The return value of this function will be passed to the `onsuccess` callback.
|
393 | transformResponse: null,
|
394 |
|
395 | // The function to check whether to call the error callback.
|
396 | shouldCallErrorCallback: null,
|
397 |
|
398 | // The function to check whether to call the success callback.
|
399 | shouldCallSuccessCallback: null
|
400 | }
|
401 | ```
|