Add support for options.headers in m.request + tests/docs

I also had to edit the mocks accordingly, so I could inspect the headers set.
This commit is contained in:
impinball 2016-12-30 02:52:00 -05:00
parent 00a3ce3657
commit 95d738bc71
4 changed files with 66 additions and 5 deletions

View file

@ -50,6 +50,7 @@ Argument | Type | Required | Descr
`options.password` | `String` | No | A password for HTTP authorization. Defaults to `undefined`. This option is provided for `XMLHttpRequest` compatibility, but you should avoid using it because it sends the password in plain text over the network.
`options.withCredentials` | `Boolean` | No | Whether to send cookies to 3rd party domains. Defaults to `false`
`options.config` | `xhr = Function(xhr)` | No | Exposes the underlying XMLHttpRequest object for low-level configuration. Defaults to the [identity function](https://en.wikipedia.org/wiki/Identity_function).
`options.headers` | `Object` | No | Headers to append to the request before sending it (applied right before `options.config`).
`options.type` | `any = Function(any)` | No | A constructor to be applied to each object in the response. Defaults to the [identity function](https://en.wikipedia.org/wiki/Identity_function).
`options.serialize` | `string = Function(any)` | No | A serialization method to be applied to `data`. Defaults to `JSON.stringify`, or if `options.data` is an instance of [`FormData`](https://developer.mozilla.org/en/docs/Web/API/FormData), defaults to the [identity function](https://en.wikipedia.org/wiki/Identity_function) (i.e. `function(value) {return value}`).
`options.deserialize` | `any = Function(string)` | No | A deserialization method to be applied to the response. Defaults to a small wrapper around `JSON.parse` that returns `null` for empty responses.
@ -404,7 +405,21 @@ function parseCSV(data) {
}
```
Ignoring the fact that the parseCSV function above doesn't handle a lot of cases that a proper CSV parser would, the code above logs an array of arrays
Ignoring the fact that the parseCSV function above doesn't handle a lot of cases that a proper CSV parser would, the code above logs an array of arrays.
Custom headers may also be helpful in this regard. For example, if you're requesting an SVG, you probably want to set the content type accordingly. To override the default JSON request type, set `options.headers` to an object of key-value pairs corresponding to request header names and values.
```javascript
m.request({
method: "GET",
url: "/files/image.svg",
headers: {
"Content-Type": "image/svg+xml; charset=utf-8",
"Accept": "image/svg, text/*"
},
deserialize: function(value) {return value}
})
```
---
@ -485,4 +500,3 @@ m.request("/api/v1/users").then(function(users) {
console.log("list of users:", users)
})
```

View file

@ -33,7 +33,7 @@ module.exports = function($window, Promise) {
}
return args
}
function request(args, extra) {
var finalize = finalizer()
args = normalize(args, extra)
@ -63,6 +63,10 @@ module.exports = function($window, Promise) {
}
if (args.withCredentials) xhr.withCredentials = args.withCredentials
for (var key in args.headers) if ({}.hasOwnProperty.call(args.headers, key)) {
xhr.setRequestHeader(key, args.headers[key])
}
if (typeof args.config === "function") xhr = args.config(xhr, args) || xhr
xhr.onreadystatechange = function() {
@ -93,7 +97,7 @@ module.exports = function($window, Promise) {
function jsonp(args, extra) {
var finalize = finalizer()
args = normalize(args, extra)
var promise = new Promise(function(resolve, reject) {
var callbackName = args.callbackName || "_mithril_" + Math.round(Math.random() * 1e16) + "_" + callbackCount++
var script = $window.document.createElement("script")

View file

@ -343,6 +343,43 @@ o.spec("xhr", function() {
done()
}, 20)
})
o("headers are set when header arg passed", function(done) {
mock.$defineRoutes({
"POST /item": function(request) {
return {status: 200, responseText: ""}
}
})
xhr({method: "POST", url: "/item", config: config, headers: {"Custom-Header": "Value"}}).then(done)
function config(xhr) {
o(xhr.getRequestHeader("Custom-Header")).equals("Value")
}
})
o("headers are with higher precedence than default headers", function(done) {
mock.$defineRoutes({
"POST /item": function(request) {
return {status: 200, responseText: ""}
}
})
xhr({method: "POST", url: "/item", config: config, headers: {"Content-Type": "Value"}}).then(done)
function config(xhr) {
o(xhr.getRequestHeader("Content-Type")).equals("Value")
}
})
o("json headers are set to the correct default value", function(done) {
mock.$defineRoutes({
"POST /item": function(request) {
return {status: 200, responseText: ""}
}
})
xhr({method: "POST", url: "/item", config: config}).then(done)
function config(xhr) {
o(xhr.getRequestHeader("Content-Type")).equals("application/json; charset=utf-8")
o(xhr.getRequestHeader("Accept")).equals("application/json, text/*")
}
})
})
o.spec("failure", function() {
o("rejects on server error", function(done) {

View file

@ -14,7 +14,13 @@ module.exports = function() {
var $window = {
XMLHttpRequest: function XMLHttpRequest() {
var args = {}
this.setRequestHeader = function(header, value) {}
var headers = {}
this.setRequestHeader = function(header, value) {
headers[header] = value
}
this.getRequestHeader = function(header) {
return headers[header]
}
this.open = function(method, url, async, user, password) {
var urlData = parseURL(url, {protocol: "http:", hostname: "localhost", port: "", pathname: "/"})
args.method = method