diff --git a/docs/client/api.html b/docs/client/api.html index c0a1ac35dc..57b150328b 100644 --- a/docs/client/api.html +++ b/docs/client/api.html @@ -1401,20 +1401,20 @@ Contents of the result object:
statusCode - Number or null
+ Number
Numeric HTTP result status code, or null on error.
-
headers() - Object
-
Return a dictionary of HTTP headers from the response.
- -
content() +
content String
-
Return the body of the HTTP response as a string.
+
The body of the HTTP response as a string.
-
data() +
data + Object or null
+
If the response headers indicate JSON content, this contains the body of the document parsed as a JSON object.
+ +
headers Object
-
Return the body of the document parsed as a JSON object.
+
A dictionary of HTTP headers from the response.
error Error
@@ -1446,6 +1446,11 @@ Example asynchronous HTTP call: {{/better_markdown}} + + +{{> api_box httphelpers}} + + diff --git a/docs/client/api.js b/docs/client/api.js index 831392779d..fa1b288f54 100644 --- a/docs/client/api.js +++ b/docs/client/api.js @@ -791,4 +791,11 @@ Template.api.httpcall = { ] }; +Template.api.httphelpers = { + id: "meteor_http_helpers", + name: "Meteor.http.[get, post, put, del] (...)", + locus: "Anywhere", + descr: ["Convience shortcuts for `Meteor.http.call` with `method` argument specified."] +}; + diff --git a/docs/client/docs.js b/docs/client/docs.js index 197c304868..329862d813 100644 --- a/docs/client/docs.js +++ b/docs/client/docs.js @@ -165,7 +165,11 @@ var toc = [ ], "Meteor.http", [ - "Meteor.http.call" + "Meteor.http.call", + {name: "Meteor.http.get", id: "meteor_http_helpers"}, + {name: "Meteor.http.post", id: "meteor_http_helpers"}, + {name: "Meteor.http.put", id: "meteor_http_helpers"}, + {name: "Meteor.http.del", id: "meteor_http_helpers"} ] ], diff --git a/packages/http/httpcall_client.js b/packages/http/httpcall_client.js index b0f2b52bd5..cd124c7e95 100644 --- a/packages/http/httpcall_client.js +++ b/packages/http/httpcall_client.js @@ -111,24 +111,28 @@ Meteor.http = Meteor.http || {}; // no HTTP response callback(new Error("network")); } else { + var response = {}; response.statusCode = xhr.status; - response.content = function() { - return xhr.responseText; - }; - response.data = function() { - return JSON.parse(response.content()); - }; - response.headers = function () { - var header_str = xhr.getAllResponseHeaders(); - var headers_raw = header_str.split(/\r?\n/); - var headers = {}; - _.each(headers_raw, function (h) { - var m = /^(.*?):(?:\s+)(.*)$/.exec(h); - if (m && m.length === 3) - headers[m[1].toLowerCase()] = m[2]; - }); - return headers; + response.content = xhr.responseText; + + response.headers = {}; + var header_str = xhr.getAllResponseHeaders(); + var headers_raw = header_str.split(/\r?\n/); + _.each(headers_raw, function (h) { + var m = /^(.*?):(?:\s+)(.*)$/.exec(h); + if (m && m.length === 3) + response.headers[m[1].toLowerCase()] = m[2]; + }); + + // only parse data if correct content type. + if (_.include(['application/json', 'text/javascript'], + response.headers['content-type'])) { + try { + response.data = JSON.parse(response.content); + } catch (err) { + response.data = null; + } }; var error = null; diff --git a/packages/http/httpcall_common.js b/packages/http/httpcall_common.js index e6755e458a..61ee09239a 100644 --- a/packages/http/httpcall_common.js +++ b/packages/http/httpcall_common.js @@ -35,4 +35,19 @@ Meteor.http = Meteor.http || {}; return url; }; -})(); \ No newline at end of file + + Meteor.http.get = function (/* varargs */) { + return Meteor.http.call.apply(this, ["GET"].concat(_.toArray(arguments))); + }; + Meteor.http.post = function (/* varargs */) { + return Meteor.http.call.apply(this, ["POST"].concat(_.toArray(arguments))); + }; + Meteor.http.put = function (/* varargs */) { + return Meteor.http.call.apply(this, ["PUT"].concat(_.toArray(arguments))); + }; + Meteor.http.del = function (/* varargs */) { + return Meteor.http.call.apply(this, ["DELETE"].concat(_.toArray(arguments))); + }; + + +})(); diff --git a/packages/http/httpcall_server.js b/packages/http/httpcall_server.js index 83761eab1f..95c6dfe297 100644 --- a/packages/http/httpcall_server.js +++ b/packages/http/httpcall_server.js @@ -108,14 +108,17 @@ Meteor.http = Meteor.http || {}; response = {}; response.statusCode = res.statusCode; - response.content = function() { - return body; - }; - response.data = function() { - return JSON.parse(response.content()); - }; - response.headers = function () { - return res.headers; + response.content = body; + response.headers = res.headers; + + // only parse data if correct content type. + if (_.include(['application/json', 'text/javascript'], + response.headers['content-type'])) { + try { + response.data = JSON.parse(response.content); + } catch (err) { + response.data = null; + } }; if (res.statusCode >= 400) diff --git a/packages/http/httpcall_tests.js b/packages/http/httpcall_tests.js index c0aa891dc8..ea881b516f 100644 --- a/packages/http/httpcall_tests.js +++ b/packages/http/httpcall_tests.js @@ -20,7 +20,7 @@ testAsyncMulti("httpcall - basic", [ test.equal(typeof result, "object"); test.equal(result.statusCode, 200); - var data = result.data(); + var data = result.data; // allow dropping of final ? (which mobile browsers seem to do) var allowed = [expected_url]; @@ -105,7 +105,7 @@ testAsyncMulti("httpcall - failure", [ test.isFalse(error); test.isTrue(result); test.equal(result.statusCode, 200); - var data = result.data(); + var data = result.data; test.equal(data.url, "/foo"); test.equal(data.method, "GET"); @@ -123,7 +123,7 @@ testAsyncMulti("httpcall - redirect", [ // should be redirected transparently to /foo test.equal(result.statusCode, 200); - var data = result.data(); + var data = result.data; test.equal(data.url, "/foo"); test.equal(data.method, "GET"); })); @@ -142,7 +142,7 @@ testAsyncMulti("httpcall - redirect", [ if (followRedirects) { // should be redirected transparently to /foo test.equal(result.statusCode, 200); - var data = result.data(); + var data = result.data; test.equal(data.url, "/foo"); test.equal(data.method, "GET"); } else { @@ -166,34 +166,29 @@ testAsyncMulti("httpcall - methods", [ function(test, expect) { // non-get methods - var test_method = function(meth, should_throw) { - var maybe_expect = (should_throw ? _.identity : expect); - var func = function() { - Meteor.http.call( - meth, url_prefix()+"/foo", - maybe_expect(function(error, result) { - test.isFalse(error); - test.isTrue(result); - test.equal(result.statusCode, 200); - var data = result.data(); - test.equal(data.url, "/foo"); - // IE <= 8 turns seems to turn POSTs with no body into - // GETs, inexplicably. - if (Meteor.is_client && $.browser.msie && $.browser.version <= 8 - && meth === "POST") - meth = "GET"; - test.equal(data.method, meth); - })); - }; - if (should_throw) - test.throws(func); - else - func(); + var test_method = function(meth, func_name) { + func_name = func_name || meth.toLowerCase(); + Meteor.http[func_name]( + url_prefix()+"/foo", + expect(function(error, result) { + test.isFalse(error); + test.isTrue(result); + test.equal(result.statusCode, 200); + var data = result.data; + test.equal(data.url, "/foo"); + // IE <= 8 turns seems to turn POSTs with no body into + // GETs, inexplicably. + if (Meteor.is_client && $.browser.msie && $.browser.version <= 8 + && meth === "POST") + meth = "GET"; + test.equal(data.method, meth); + })); }; + test_method("GET"); test_method("POST"); test_method("PUT"); - test_method("DELETE"); + test_method("DELETE", 'del'); }, function(test, expect) { @@ -205,7 +200,7 @@ testAsyncMulti("httpcall - methods", [ test.isFalse(error); test.isTrue(result); test.equal(result.statusCode, 200); - var data = result.data(); + var data = result.data; test.equal(data.body, "Hello World!"); })); @@ -216,7 +211,7 @@ testAsyncMulti("httpcall - methods", [ test.isFalse(error); test.isTrue(result); test.equal(result.statusCode, 200); - var data = result.data(); + var data = result.data; test.equal(data.body, {greeting: "Hello World!"}); })); } @@ -239,7 +234,7 @@ testAsyncMulti("httpcall - http auth", [ test.isFalse(error); test.isTrue(result); test.equal(result.statusCode, 200); - var data = result.data(); + var data = result.data; test.equal(data.url, "/login?"+password); })); @@ -264,7 +259,7 @@ testAsyncMulti("httpcall - headers", [ test.isTrue(result); test.equal(result.statusCode, 200); - var data = result.data(); + var data = result.data; test.equal(data.url, "/foo-with-headers"); test.equal(data.method, "GET"); test.equal(data.headers['test-header'], "Value"); @@ -278,8 +273,8 @@ testAsyncMulti("httpcall - headers", [ test.isTrue(result); test.equal(result.statusCode, 201); - test.equal(result.headers()['a-silly-header'], "Tis a"); - test.equal(result.headers()['another-silly-header'], "Silly place."); + test.equal(result.headers['a-silly-header'], "Tis a"); + test.equal(result.headers['another-silly-header'], "Silly place."); })); } ]); @@ -304,7 +299,7 @@ testAsyncMulti("httpcall - params", [ test.isTrue(result); test.equal(result.statusCode, 200); if (method !== "HEAD") { - var data = result.data(); + var data = result.data; test.equal(data.method, method); test.equal(data.url, expect_url); test.equal(data.body, expect_body); diff --git a/packages/http/test_responder.js b/packages/http/test_responder.js index ce9569d132..c4070c9b08 100644 --- a/packages/http/test_responder.js +++ b/packages/http/test_responder.js @@ -63,6 +63,7 @@ var respond = function(req, res) { response_string = JSON.stringify(response_data); res.statusCode = 200; + res.setHeader("Content-Type", "application/json"); res.end(response_string); });