Request Service
Provides a fully customizable Library for handling API using Request Repositories and Stubs.
Initialisation
- Create your own ES-6 classes implementing "RequestClient" and "RequestHandler" Interfaces from the package.
import {RequestClient} from '@argab/request-service'
import axios from 'axios'
const _axios = (config) => axios.create(config)
export default class extends RequestClient {
get({headers, uri, params}) {
return _axios({headers}).get(uri, params)
}
post({headers, uri, params}) {
return _axios({headers}).post(uri, params)
}
patch({headers, uri, params}) {
return _axios({headers}).patch(uri, params)
}
put({headers, uri, params}) {
return _axios({headers}).put(uri, params)
}
delete({headers, uri, params}) {
return _axios({headers}).delete(uri, params)
}
}
import {RequestHandler} from '@argab/request-service'
export default class extends RequestHandler {
isSuccess(response) {
}
isError(response) {
}
onSuccess(response) {
}
onError(response) {
}
onCatch(error) {
}
onFinally(data) {
}
before(data) {
}
after(response) {
}
afterCatch(error) {
}
afterFinally(data) {
}
}
- Initialise the Request Service and connect it to your App:
import {RequestService} from '@argab/request-service'
import ApiClient from './src/api/ApiClient'
import ApiHandler from './src/api/ApiHandler'
MyApp.prototype.request = new RequestService({
config: {
client: ApiClient,
handler: ApiHandler
}
})
new MyApp()
Simple request
import ApiHandler from './src/api/ApiHandler'
import SomeHandler from './src/api/SomeHandler'
import SomeClient from './src/api/SomeClient'
this.request
.config({
handler: [SomeHandler, ApiHandler],
client: SomeClient,
headers: {'Content-Type': 'application/json;charset=UTF-8'},
log: false
})
.unlog()
.headers({'Content-Type': 'application/json;charset=UTF-8'})
.json()
.encode()
.form()
.html()
.stream()
.post('http://some.url', {parameters})
.success(response => {})
.error(response => {})
.catch(error => {})
.finally(requestData => {})
Request Repositories And Stubs
Request repositories allow you to move the complex logic of creating requests to a separate namespace (directory)
import {RequestService} from '@argab/request-service'
import ApiClient from './src/api/_clients/ApiClient'
import ApiHandler from './src/api/_handlers/ApiHandler'
MyApp.prototype.request = new RequestService({
getRepo: (path) => {
const Repo = require(`./api/${path}`).default
return new Repo
},
getStub: (path) => {
const Stub = require(`./api/_stubs/${path}`).default
return new Stub
},
useStubs: true,
config: {
client: ApiClient,
handler: ApiHandler
}
})
new MyApp()
import {RequestRepository} from '@argab/request-service'
export default class extends RequestRepository {
getOrders(params) {
return this.client.get('http://some.url/orders', params)
}
}
import {RequestRepository} from '@argab/request-service'
export default class extends RequestRepository {
getOrders(params) {
return this.client.stubData({SOME_STUB_DATA}).get('/orders', params)
}
}
this.request.repo('orders').getOrders({params}).then(...).error(...)
this.request.stub('orders').getOrders({params}).then(...).error(...)
Use of Loaders
The "Loader" meaning is a Tool that indicates a live cycle of the request. For example a Loading Spinner in the HTML Document.
import {RequestLoader} from '@argab/request-service'
class MyLoader extends RequestLoader {
_data
pending
constructor(data) {
super()
this._data = data
}
start() {
console.log('Requests in pending status: ', this.pending)
console.log('Request pending: ', `${this._data.method.toUpperCase()} ${this._data.uri}...`)
}
end() {
console.log('Request complete: ', `${this._data.method.toUpperCase()} ${this._data.uri}.`)
}
}
import {RequestService} from '@argab/request-service'
import ApiClient from './src/api/_clients/ApiClient'
import MyLoader from './src/api/_loaders/MyLoader'
import MyCustomLoader from './src/api/_loaders/MyCustomLoader'
MyApp.prototype.request = new RequestService({
config: {
client: ApiClient,
loader: MyLoader,
useLoader: true
}
})
const app = new MyApp()
app.request
.config({loader: MyCustomLoader})
.useLoader()
.bg()
.get('http://some.url').success(...).error(...).catch(...).finally(...)
Extending Request And RequestMiddleware
By Passing argument named "extend" allows to inject any custom pre-request and post-request handling methods to
the Base Request's prototype.
import {RequestService} from '@argab/request-service'
import ApiClient from './src/api/_clients/ApiClient'
import ApiHandler from './src/api/_handlers/ApiHandler'
MyApp.prototype.request = new RequestService({
config: {
client: ApiClient,
handler: ApiHandler
},
extend: {
middleware: {
awesome: function () {
console.log('This is my awesome middleware function!')
this.config({headers: {'X-AwesomeHeader': 'v1.0.0'}})
}
},
request: {
done: function (messageOnSuccess) {
console.log(`This is what my ApiHandler would notify about at response success: `, messageOnSuccess)
this.data.done = messageOnSuccess
},
alert: function (messageOnError) {
console.log(`This is what my ApiHandler would notify about at response error: `, messageOnError)
this.data.alert = messageOnError
}
}
}
})
import {RequestHandler} from '@argab/request-service'
export default class extends RequestHandler {
_data
constructor(data) {
super()
this._data = data
}
isSuccess(response) {
return true
}
after(response) {
const notifySuccess = this._data.done;
const notifyError = this._data.alert;
if (this.isSuccess(response) && notifySuccess) {
console.log(notifySuccess)
} else if (this.isError(response) && notifyError) {
console.error(notifyError)
}
}
}
const app = new MyApp()
app.request.awesome().get('/posts').done('Wow, that`s awesome!').alert('Ooops...')
Output from tests:
This is my awesome middleware function!
Requests in pending status: 1
Request pending: GET /posts...
This is what my ApiHandler would notify about at response success: Wow, that`s awesome!
This is what my ApiHandler would notify about at response error: Ooops...
Wow, that`s awesome!
Request complete: GET /posts.
Retrying the Request
Request retrying available both from the Request Handler and Request call:
import {RequestHandler} from '@argab/request-service'
export default class extends RequestHandler {
onFinally() {
this.retry((data) => new Promise(resolve => {
resolve(true)
}))
this.retry(true)
this.retry(data => {
data.retryChain = ({chain}) => {
chain.find(c => c.method === 'error').args[0] = () => {
console.log('"error" method has been overriden.')
}
return chain
}
return true
})
}
}
const result = await app.request
.awesome()
.get('/posts')
.error(() => { throw 'Oops!' })
.retryMaxCount(3)
.retryTimeout(3000)
.retryChain(({chain}) => {
chain.find(c => c.method === 'error').args[0] = () => {
console.log('"error" method has been overriden.')
}
return chain
})
.retryOnCatch(data => {
return new Promise(res => {
setTimeout(() => {
console.error('Awesome error: ', data.dataError)
res(true)
}, 3000)
})
})
console.log(result)
Retry Methods:
retry (resolve) {}
retryOnCatch (resolve) {}
retryChain (callback) {}
retryMaxCount (count) {}
retryTimeout (miliseconds) {}