earbuds-http
v5.0.0
Published
An http module for Transplace web applications
Downloads
2
Readme
Earbuds Http
An HTTP library to standardize ajax requests to a Transplace API.
Installation
npm install earbuds-http
earbuds-http isn't currently pre-compiled, so you may need to modify your webpack config to deal with it.
// webpack.base.conf.js
module.exports = {
entry: [ /* ... */ ],
resolve: [ /* ... */ ],
module: {
rules: {
{ /* eslint rules */ },
{ /* vue-loader rules */ },
{
/* babel rules */
test: /\.js$/,
loader: 'babel-loader',
include: [
resolve('src'),
resolve('test'),
// transpile all packages named earbuds{whatever}
new RegExp(resolve(['node_modules', 'earbuds.*']), 'i'),
]
}
}
}
};
Axios
earbuds-http is built on top of axios. Anything that axios does Earbuds-http should do, too.
earbuds-http adds caching and custom server response handling to base axios.
https://github.com/mzabriskie/axios
Usage
Basics
ebHttp.get(url, [options])
ebHttp.post(url, data, [options])
Common Options
params
- the URL parameters to be sent with the request. Must be a plain object or a URLSearchParams objectparams: { ID: 12345 },
data
- the data to be sent as the request body Only applicable for request methods 'PUT', 'POST', and 'PATCH' When notransformRequest
is set, must be of one of the following types:- string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
- Browser only: FormData, File, Blob
- Node only: Stream, Buffer
data: { firstName: 'Fred' },
cache
- whether or not to cache the response. boolean.{cache: true}
cacheTimeToLive
- how long the data should be cached. the value is milliseconds until the cache should expire{cacheTimeToLive: 5000}
updateCache
- if true, the current cached value is ignored and the new value is saved in it's place{cacheTimeToLive: true}
More Options
see https://github.com/mzabriskie/axios#request-config
Extension Points
Extend earbuds-http by using axios's extension points (which were inspired by angular's $http module) https://github.com/mzabriskie/axios#interceptors
Handling the server response
earbuds-http correctly handles api entity responses from the server.
An ApiEntity response looks like this:
{
success: true,
errors: [ ],
tid: null,
data: {
domainId: null,
accountId: -1,
accountName: null,
// ...
}
}
earbuds-http handles automatically handles the success
flag. If true, the promise is resolved with the contents of the data field. Otherwise, the promise is rejected with a list of errors.
Currently the tid
(transaction-id) field is not managed.
Handling an AuthenticationError response
Add a response interceptor to catch the AuthenticationError and handle it
// signInRequiredResponseInterceptor.js
import AuthenticationError from 'earbuds-http/src/errors/AuthenticationError';
// todo - confirm that this is the best generic login URL to try
const LOGON_URL_BEST_GUESS = process.env.NODE_ENV !== 'production'
? '/security/baseLogon.do'
: '/00-tms-logon-redirect.php';
function handleSignInRequired(error) {
// Returning a non-resolving promise prevents the api request from resolving
// at all. E.g. if this happens in a beforeEnter navigation guard in the
// router, it will stop the page from loading while waiting for the redirect
// to resolve.
return new Promise(() => {
if (error.response && error.response.data && error.response.data.redirect) {
window.location.href = error.response.data.redirect;
} else {
console.warn('ERROR - SIGN IN REQUIRED', 'No redirect url provided. Trying best guess.', LOGON_URL_BEST_GUESS);
window.location.href = LOGON_URL_BEST_GUESS;
}
});
}
export default function rejectedHandler(err) {
if (err && (err instanceof AuthenticationError || err.name === 'AuthenticationError')) {
return handleSignInRequired(err);
}
return err;
}
// BaseApi.js
import ebHttp from 'earbuds-http';
import combineUrls from 'axios/lib/helpers/combineURLs';
import signInRequiredResponseInterceptor from './signInRequiredResponseInterceptor';
const TMS_API_URL = '/tms/api/v1/';
class BaseTmsApi {
constructor(url) {
const baseUrl = combineUrls(TMS_API_URL, url);
this.ebHttp = ebHttp.create({
baseURL: baseUrl,
headers: { 'Content-Type': 'application/json', Accept: 'application/json' }
});
// Handle sign-in required errors
this.ebHttp.interceptors.response.use(null, signInRequiredResponseInterceptor);
}
}
export { BaseTmsApi };
export default BaseTmsApi;
Caching
Cached calls
Both get
and post
calls can be cached.
var url = '/user/123/details';
var a = instance.get(url, {cache:true});
var b = instance.get(url, {cache:true});
var c = instance.get(url, {params: {includeAddress: true}, cache: true});
var d = instance.get(url, {params: {includeAddress: true}, cache: true});
a === b; // true
c === d; // true
a === c; // false. Although the url is the same, the options are not.
Subsequent calls to that url with the same options will used cached data instead of hitting the server.
Time To Live
You can automatically expire cached data after a specified number of milliseconds by including the cacheTimeToLive
parameter.
var url = '/user/123/details';
var a = instance.get(url, {cache:true, cacheTimeToLive: 10000});
setTimeout(function () {
var c = instance.get(url, {cache:true, cacheTimeToLive: 10000});
a === c; // true
}, 5000);
setTimeout(function () {
var d = instance.get(url, {cache:true, cacheTimeToLive: 10000});
a === d; // false
}, 20000);
Example
// userApi.js
import ebHttp from 'earbuds-http';
const BASE_URL = './api/user';
export default class Api {
_httpInstance;
constructor(url) {
if (!url) {
throw new Error('url must be provided');
}
this._httpInstance = ebHttp.create({
baseURL: path.join(BASE_URL, url)
});
}
get http() {
return this._httpInstance;
}
getSecurityContext() {
// url -> ./api/user/securityContext/
// cached for the entirety of the javascript session
return this.http.get('/securityContext', { cache: true });
}
getUserDetail(userId) {
// url -> ./api/user/userDetail/userId
// not cached at all
return this.http.get(`/userDetail/${userId}`, { cache: false });
}
getMapData(showMapPaths, mapStyle) {
// url -> ./api/user/getMapData/userId?showMapPaths=true&mapStyle=SQUARE
// cached for 10 seconds
return this.http.get('/userDetail/${userId}', {
params: {showMapPaths, mapStyle},
cache: true,
cacheTimeToLive: 10000
});
}
}
// consumer.js
import userApi from './userApi';
userApi.getSecurityContext()
.then(securityContext => console.log(securityContext))
.catch(errors => toastr.danger(errors.join(', ')));
// ...
Development
You can develop npm packages locally without having to push to test your changes
https://docs.npmjs.com/cli/link
- Git clone this repository
- In earbuds-http,
$ npm link
- In a project using earbuds-http,
$ npm link earbuds-http
Once you're done developing, use npm version to push your changes
https://docs.npmjs.com/cli/version
- In earbuds-http, make sure everything is committed
- In earbuds-http,
$ npm version [major|minor|patch]
- In a project using earbuds-http,
- first time install:
$ npm install earbuds-http
- upgrade:
$ npm upgrade earbuds-http
- first time install: