The idea behind the provider model is to create back-end agnostic code that depends on a provider plugin to connect and and communicate with the main service. Plugins provide communication layer so that the application itself can deal only with idealized data and straight-forward verbal actions. Decoupling the communication layer from the front-end code allows for a cleaner and more easily testable application.
This works especially well when using the notion of a central event bus with font-end components publishing via the bus requests for data and user actions and subscribe to relevant updates. The provider in turn subscribes to the actions it can specifically handle, communicates this to the back-end and then publishes the result on the event bus for any listening components.
There are a few addition gains that make this ideal for debugging, integration and end to end testing. Since the provider is only a subscriber to specific events and not the sole consumer, more than one provider can be used by the application without changing any code or needing to proxy messages between back-end servers, components or connections.
This enable both multiple providers when the backend requires multiple and distinct connections as well as the ability to include a debugging, logging, or replay provider along side any real back-end providers.
Providers can also be set up as Node.js modules so that they can be independently developed and maintained, and then included in the front-end application using semantic versioning to ensure the right version in included.
Vue's plugin architecture makes this especially simple. Below is a bit of not-quite-psuedo code to illustrate how this works in practice.
// Event Bus
Vue.prototype.$events = new Vue({
methods: {
$send(object) {
this.$emit(constants.message.send, object);
}
}
});
// Providers
ProviderWebsocket.install = function (Vue, options) {
const capabilities = {
authentication: true,
graphics: true,
somethingCool: true
};
const ws = new WebSocket('ws://localhost:8082');
// Message received
ws.on('message', function(message) {
Vue.prototye.$events.$send(message.type, message.data);
});
Vue.prototype.$events.$on('request', function(message) {
ws.send(message.data);
});
Vue.prototype.$events.$on('capabilities', function(message) {
Vue.prototype.$events.$send('capable', capabilities);
});
Vue.prototype.$events.on('init', {
ws.connect();
});
};
ProviderLogger.install = function(Vue, options) {
Vue.prototype.$events.$on('request', function(message) {
console.log('REQUEST', message);
});
Vue.prototype.$events.$on('data', function(message) {
console.log('DATA', message);
});
Vue.prototype.$events.on('init', {
console.log('Logger listening on event bus');
});
};
ProviderRest.install = function(Vue, options) {
const capabilities = {
getData: true
};
Vue.prototype.$events.$on('get', function(message) {
axios.get(message.url).
then(function(response) {
Vue.prototype.$events.$send(response.type, response.data);
});
});
Vue.prototype.$events.$on('capabilities', function(message) {
Vue.prototype.$events.$send('capable', capabilities);
});
};
// Include all providers simultaneously as plugins
Vue.use(ProviderWebsocket);
Vue.use(ProviderRest);
Vue.use(ProviderLogger);