Requests
HTTP client
We aim to have a consistency between the server and the client when performing HTTP requests. This could be easily
solved requiring an external HTTP client which works on bot Node.js (i.e. axios),
but as we already have Mithril's own m.request
API on the client, we are going
to use it also on the server.
At the beginning of our tutorial, you might have noticed the following line at the top of the entry point of our server
side app, server.js
:
global.window.XMLHttpRequest = require('w3c-xmlhttprequest').XMLHttpRequest;
This dependency is required to allow server-side XMLHttpRequest like W3C spec on Node.js, so we can consistently use
Mithril's own m.request
API on both server and client.
Since we want a specific control on our how the requests are done, how the data is processed and how the errors are
managed, we build our own wrapper around Mithril's m.request
, in app/request.js
:
const m = require('mithril');
const request = (options) => {
const args = Object.assign({}, options, { extract: (xhr) => {
const isJSON = xhr.getResponseHeader('Content-Type').indexOf('application/json') !== -1;
if (xhr.status >= 400) {
throw new Object({
status: xhr.status,
message: xhr.statusText
});
} else {
return isJSON ? JSON.parse(xhr.responseText) : xhr.responseText;
}
} });
return m.request(args)
.catch(err => Promise.reject(err));
};
We can then define our own get
and post
methods based on our request
function:
module.exports = {
get: (url, args) => {
let options = {};
options.method = 'GET';
options.url = url;
if (args && typeof args === 'object') {
options = Object.assign(options, args);
}
return request(options);
},
post: (url, data, args) => {
let options = {};
options.method = 'POST';
options.url = url;
options.data = data;
if (args && typeof args === 'object') {
Object.assign(options, args);
}
return request(options);
}
};
Request functions
For convenience, we are going to group all the HTTP request functions in the same file (app/resources.js
), which will
look like:
const request = require('./request.js');
const port = process.env.PORT || 3000;
const localUrl = 'http://' + (process.browser ? window.location.host : '127.0.0.1:' + port);
const localData = localUrl + '/docs';
const manageErrors = (err) => {
return Promise.reject(err);
};
module.exports = {
getContent: (content) => request.get(`${localData}/${content}.json`)
.then(data => data)
.catch(manageErrors),
// ...
};
Since m.request
returns a Promise, we define all our request functions to do the same, to be used in our async main
components.