radi-fetch
Version:
`radi-fetch` is the official HTTP client for [Radi.js](https://radi.js.org). It deeply integrates with Radi for seamless application building.
184 lines (164 loc) • 4.51 kB
JavaScript
export const version = '0.3.23';
// Pass config to initiate things
export default ({
r,
l,
mount,
headless,
Component,
}, config = {}) => {
let prefix = (config.baseUrl || '').replace(/\/$/, '');
let dummy = config.dummy;
let dummyData = config.dummyData || {};
let fetchdummy = (type, key, cb) => {
setTimeout(() => {
cb(dummyData[type] && dummyData[type][key] || null)
}, config.dummyTimeout || 100)
}
let HTTP = function HTTP(t, url, params, headers, loading) {
this.localDummy = config.dummy
this.url = url
this.id = url + ''
this.type = t
this.start = () => loading.start(this.id)
this.end = () => loading.end(this.id)
this.http = new XMLHttpRequest()
this.headers = Object.assign(config.headers || {}, headers || {})
this.params = JSON.stringify(params)
this.resolve = () => {
this.end()
};
this.reject = e => {
console.error('[Radi Fetch] WARN: Request caught an error.\n', e);
this.end()
};
let n = url.split('?').length - 1
if (t === 'get')
for (let i in params) {
url = url.concat(((!n)?'?':'&') + i + '=' + params[i])
n += 1
}
this.http.open(t, prefix + url, true)
for (let h in this.headers) {
this.http.setRequestHeader(h, this.headers[h])
}
// Allows to abort request
this.abort = (...args) => this.http.abort(...args)
this.tag = key => (this.id = key, this)
}
HTTP.prototype.dummy = function (status = true) {
this.localDummy = status;
return this
}
HTTP.prototype.catch = function (ERR) {
if (typeof ERR === 'function') {
this.reject = (...args) => {
ERR(...args)
this.end()
};
}
return this
}
HTTP.prototype.then = function then(OK, ERR) {
this.start()
if (typeof OK === 'function') {
this.resolve = (...args) => {
OK(...args)
this.end()
};
}
if (typeof ERR === 'function') {
this.reject = (...args) => {
ERR(...args)
this.end()
};
}
if (this.localDummy || dummy) {
fetchdummy(this.type, this.url, data => {
this.resolve({
headers: '',
status: 'dummy',
response: JSON.stringify(data),
text: () => JSON.stringify(data),
json: () => data,
});
})
return this;
}
let self = this
this.http.onreadystatechange = function(e) {
let res = this
if (res.readyState === XMLHttpRequest.DONE) {
let h = {
headers: self.http.getAllResponseHeaders(),
status: res.status,
response: res.response
}
if (res.status === 200) {
h.text = function() { return res.responseText }
h.json = function() {
try {
return JSON.parse(this.text());
}
catch(error) {
console.error('[Radi Fetch] WARN: Response is not JSON, using fallback to empty JSON.\n', error);
return {};
}
}
self.resolve(h)
} else {
self.reject(h)
}
}
}
this.http.send(this.params)
return this
}
class Fetch extends Component {
get(u, p, h) { return new HTTP('get', u, p, h, this.$loading) }
post(u, p, h) { return new HTTP('post', u, p, h, this.$loading) }
put(u, p, h) { return new HTTP('put', u, p, h, this.$loading) }
delete(u, p, h) { return new HTTP('delete', u, p, h, this.$loading) }
options(u, p, h) { return new HTTP('options', u, p, h, this.$loading) }
head(u, p, h) { return new HTTP('head', u, p, h, this.$loading) }
}
class Loading extends Component {
state() {
return {
$any: false,
$count: 0,
}
}
start(key) {
if (this.state[key]) return false
this.setState({
[key]: true,
$count: this.state.$count + 1,
$any: !!(this.state.$count + 1),
});
}
end(key) {
this.setState({
[key]: false,
$count: this.state.$count - 1,
$any: !!(this.state.$count - 1),
});
}
run(key, fn) {
if (this.state[key]) return false
this.start(key);
fn(cb => {
if (typeof cb === 'function') cb();
this.end(key);
})
}
}
// Initiates loading component
headless('loading', Loading);
// Initiates fetch component
headless('fetch', Fetch);
return {
config,
Fetch,
};
};