practikal-library v0.7.1
practikal-library
Functional library which contains a useful set of functions for building small-size/mid-size web applications.
Goals
The library is built targeting some goals:
- provide essential functions for building modern web applications.
- 0 dependencies - 3rd party framework and library agnostic: you don't need any module from React, Angular, Vue, Aurelia, Ember, etc. but you can use it with any of them.
- everything is pluggable/extensible (loggers, fetch middlewares, validators, validation languages so).
- functions are written following functional programming principles (immutability, purity, composability - currying, partial-applications, high-order functions).
- each module is completely independent and does not refer any other library module.
- tiny: the unminified code is 13 KB (ES2015/ES6).
- functions should be as simple as possible.
- FP on/off OOP.
Description
The library contains functions for:
- logging messages.
- fetching data.
- validating objects.
- publishing/subscribing to events.
caching data.
All modules are stateless. Each module contains just pure functions. Index.ts file contains just impure functions (working with cache make them impure).
All modules are totally independent of each other; the only place where modules are glued together is index.ts file.
There are 2 different ways to use library:
- recommended and simplest way (using useLibrary function).
- without calling useLibrary (see the logging usage paragraph).
Install
npm i practikal-library --save
npm i https://git@github.com/dragos-tudor/practikal-library#master --save
Usage
Start using library
import { useLibrary } from 'practikal-library';
useLibrary();
useLibrary({ logLevel: 'TRACE' }); // or with other log level
Using useLibrary function will initialize the library with all required plumbing.
The implicit log level is 'INFO'.
Logging
Functions for:
- logging different kind of messages: trace, debug, info, warn, error.
- adding new loggers;
- changing current logging level;
Simple logging calls
import { trace, debug, info, warn, error } from 'practikal-library';
trace('msg');
debug('msg');
info('msg');
warn('WARN', ['msg1', 'msg2']);
error('msg');
error(Error('msg'));
Using useLibrary will automatically add console logger and will set provided current log level.
Adding a new logger
import { addLogger } from 'practikal-library';
const popupLogger = (logLevel, ...data) => { switch(logLevel) { case 'INFO': /*...*/ }; };
addLogger(popupLogger);
Changing current log level
import { setLogLevel } from 'practikal-library';
setLogLevel('WARN');
Using logging without calling useLibrary (not recommanded)
import { info, consoleLogger } from 'practikal-library/logging';
info('INFO', [consoleLogger])('msg');
Fetch
Functions for:
- fetching (json) data (using Fetch API).
- adding new middlewares.
Simple json fetch calls
import { getJson, putJson, postJson, deleteJson } from 'practikal-library';
getJson('http://foo.com/bar');
getJson('http://foo.com/bar', { barName: 'test bar' });
putJson('http://foo.com/bar', { barName: 'test bar' });
postJson('http://foo.com/bar', { barId: 1, barName: 'test bar' });
deleteJson('http://foo.com/bar', { barId: 1 });
Simple generic fetch call
import { fetchData, getJsonRequest } from 'practikal-library';
const request = getJsonRequest('GET', { barName: 'test bar' });
fetchData('http://foo.com/bar', request);
Using useLibrary will automatically add logger middleware, request middleware (request settings uniformization) and retry middleware (apply retry policy in case of network error - 5 times at 200ms interval).
Middlewares (see Asp.Net Core middlewares) are additional layers on top of fetchData function. The middlewares are added (and chained) at runtime ensuring that all http requests will pass through them until to reach fetchData function.
Adding base url middleware
import { addMiddleware, getAbsoluteUrl, getJson } from 'practikal-library';
const baseUrlMiddleware = (next) => (url, request) =>
next(getAbsoluteUrl(url, 'http://foo.com'), request)
addMiddleware(baseUrlMiddleware);
getJson('/bar', null); // fetch json from url 'http://foo.com/bar'
In the same way could be added other kind of middlewares (antiforgery header middleware).
Validation
Functions for:
- validating objects and values.
- using new validation languages.
- using custom validators.
- adding/changing validation messages (for custom validators or changing existing validator message).
Validating object
import { validate, isRequired } from 'practikal-library';
const validObj = { field1: 'a' };
const invalidObj = { field1: '' };
const validations = { field1: [ isRequired ] }
validate(validObj, validations); // output: { field1: '', isValid: true }
validate(invalidObj, validations); // output: { field1: 'Value is required', isValid: false }
Using new validation language
import { setValidationLanguage } from 'practikal-library';
const frValidation = { required: 'Valeur est requise' /* ... other validators */ };
setValidationLanguage(frValidation);
Adding/changing validator message for current language
import { getValidationLanguage, setValidationLanguage, setValidatorMessage } from 'practikal-library';
let language = getValidationLanguage();
language = setValidatorMessage('required', 'custom message', language);
setValidationLanguage(language);
Using new custom validator
import { setValidationLanguage, getValidationLanguage, isEmpty } from 'practikal-library';
// define contains validator
const contains = (val: string, elem: string) =>
!isEmpty(val) && val.indexOf(elem) >= 0 ? null : getValidationLanguage()['contains'].replace('#elem', elem)
// set english contains validator message
setValidatorMessage('contains', 'Value not contains "#elem"', language);
Publisher-Subscriber
Functions for:
- publishing events.
- subscribing to events.
- unsubscribing from events.
Using publisher-subscriber functions
import { publish, subscribe, unsubscribe } from './practikal-library';
subscribe('event1', 'subscriber1', (data) => console.log(data));
publish('event1', "test"); // output: "test"
unsubscribe('event1', 'subscriber1');
publish('event1', "test"); // output:
Subscribing to one event will not return an subscription id (like usual).
Unsubscribing from one event is made based on subscription name.
Caching
Functions for:
- adding data to cache.
- removing data from cache.
- getting data from cache.
Using caching functions
import { addToCache, removeFromCache, getFromCache } from './practikal-library';
addToCache('k1', { val: 1 })
getFromCache('k1') // output: { val: 1 }
removeFromCache('k1')
getFromCache('k1') // output: null
Development
Clone
git clone https://github.com/dragos-tudor/practikal-library.git
Install
npm install
Build
npm run build
Test
npm run test
/* or for continous testing (CT) */
npm run test.watchAll
npm run test.watch "validation\.spec\.ts"
npx jest --watchAll
/*...*/
Rules:
As a general defining rules:
- interfaces define structures.
- types are used to define functions or union types.
- functions are declared as arrow functions.
- object literals declare structures.
- classes are NOT used.
As a general naming rule interfaces and types are uppercases, functions and literal objects are lowercases.
As a general positioning rule each module start with exported interfaces and types definitions, functions and object literals declarations and then the private ones.
ES2015/ES6 and CommonJs supported module systems (default ES2015/ES6).