Skip to content

Commit

Permalink
Added client with fetch support (0.1.0) (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
ancamcheachta committed Feb 18, 2018
1 parent 279166b commit a52cdc1
Show file tree
Hide file tree
Showing 11 changed files with 455 additions and 1 deletion.
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
language: node_js
node_js:
- "7"
after_success: "npm run coverage"
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
# cealloga-client-es
A cealloga client for ECMAScript
[![Build Status](https://travis-ci.org/ancamcheachta/cealloga-client-es.svg?branch=master)](https://travis-ci.org/ancamcheachta/cealloga-client-es)
[![Coverage Status](https://coveralls.io/repos/ancamcheachta/cealloga-client-es/badge.svg)](https://coveralls.io/r/ancamcheachta/cealloga-client-es)
[![npm version](https://badge.fury.io/js/cealloga-client-es.svg)](https://badge.fury.io/js/cealloga-client-es)

A [cealloga](https://github.com/ancamcheachta/cealloga) client for ECMAScript
5 changes: 5 additions & 0 deletions fixtures/barchart.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name":"barchart",
"label":"Colour Total Bar Chart",
"body":"(ceallog)=>{let colours=ceallog.vars.colours,coloursMap={},chartData={labels:[],series:[]};if(colours){colours.forEach(c=>coloursMap[c.name]=coloursMap[c.name]+1||1)}for(var name in coloursMap){let total=coloursMap[name];chartData.labels.push(name);chartData.series.push(total)}return chartData;}"
}
1 change: 1 addition & 0 deletions fixtures/colours.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"colours": [{"name": "blue"}, {"name": "yellow"}, {"name": "red"}, {"name": "yellow"}]}
12 changes: 12 additions & 0 deletions fixtures/exec-barchart-200.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"labels":[
"blue",
"yellow",
"red"
],
"series":[
1,
2,
1
]
}
10 changes: 10 additions & 0 deletions fixtures/publish-barchart-200.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"body":"(ceallog)=>{let colours=ceallog.vars.colours,coloursMap={},chartData={labels:[],series:[]};if(colours){colours.forEach(c=>coloursMap[c.name]=coloursMap[c.name]+1||1)}for(var name in coloursMap){let total=coloursMap[name];chartData.labels.push(name);chartData.series.push(total)}return chartData;}",
"compiled":true,
"created_date":"2018-01-18T20:41:04.849Z",
"id":"5a610660158ffae3135b7c7e",
"label":"Colour Total Bar Chart",
"name":"barchart",
"published":true,
"service":"/cealloga/barchart"
}
10 changes: 10 additions & 0 deletions fixtures/validate-barchart-200.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compiled":true,
"id":"5a610660158ffae3135b7c7e",
"created_date":"2018-01-18T20:41:04.849Z",
"label":"Colour Total Bar Chart",
"message":"Resource retrieved successfully.",
"name":"barchart",
"published":false,
"service":"/cealloga/_test/5a610660158ffae3135b7c7e"
}
237 changes: 237 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
'use strict';
/**
* @desc Cealloga rest API client for the browser.
* @since 0.1.0
* @author An Camchéachta <ancamcheachta@protonmail.com>
*/

import * as util from './util';

/**
* @desc A map of endpoint constants, where key is an identifier in the code,
* and value is the service endpoint.
*
* NOTE: All service endpoints should be relative.
* @since 0.1.0
*/
const endpoints = {
ceallogaDev: '/cealloga/_test',
ceallogaProd: '/cealloga',
codeList: '/code',
codePublish: '/code/publish',
codeRecord: '/code',
codeUnpublish: '/code/unpublish',
codeValidate: '/code/validate'
};

/**
* @desc Returns input options for `GET` request to be used by Fetch API.
* @returns {Object} Fetch request input options.
* @since 0.1.0
*/
const get = () => {
return {
method: 'GET',
mode: 'same-origin',
headers: new Headers({'Content-Type': 'application/json'})
};
};

/**
* @desc Returns input options for `POST` request to be used by Fetch API.
* @param {Object} body Request body.
* @returns {Object} Fetch request input options.
* @since 0.1.0
*/
const post = body => {
return {
method: 'POST',
mode: 'same-origin',
body: JSON.stringify(body),
headers: new Headers({'Content-Type': 'application/json'})
};
};

/**
* @desc Returns an encoded query string from a query object.
* @param {Object} query Unencoded object to be converted to a query string.
* @returns {string} Encoded query string.
* @since 0.1.0
*/
const queryString = query => {
let qs = '';

Object.keys(query).forEach(param => {
let value = encodeURIComponent(query[param]);

qs += `${param}=${value}&`;
});

return qs;
};

/**
* @desc Performs request using Fetch API.
* @param {string} uri Request URI.
* @param {string} method Request method. Currently supported: `GET`, `POST`.
* @param {Object} body Request body.
* @param {function} callback Function with params `err`, `result`, `response`.
* @returns {Promise} Promise. This is a no-op object as the callback handles
* the request results.
* @since 0.1.0
* @see https://developer.mozilla.org/en-US/docs/Web/API/Response
*/
const request = (uri, method, body, callback) => {
let fetchHandler, res;

switch (method) {
case 'GET':
fetchHandler = get();
break;
case 'POST':
fetchHandler = post(body);
break;
default: /* istanbul ignore next */
break;
}

return fetch(uri, fetchHandler)
.then(response => {
res = response;
response.json()
.then(json => responseJsonThen(res, callback)(json))
.catch(err => callback(err, null, res));
}).catch(err => callback(err, null, null));
};

/**
* @desc Closure used when fetch response `json()` promise is resolved.
* @param {Response} response Fetch API response object.
* @param {function} callback Function with params `err`, `result`, `response`.
* @returns {function} Closure with param `result` that, when called, executes
* callback.
* @since 0.1.0
* @see https://developer.mozilla.org/en-US/docs/Web/API/Response
*/
const responseJsonThen = (response, callback) => {
return result => {
let fetched = util.fetch(result);

result = fetched.isMock() ? fetched.json() : result;

return callback(null, result, response);
};
};

/**
* @desc Ceallóga rest API client class.
* @since 0.1.0
*/
class ApiClient {
constructor(options) {
options = options || {};

this.cealloga = new Cealloga(this);
this.code = new Code(this);
this.host = // eslint-disable-next-line
'host' in options ? options.host
: /^((?:http:|https:)\/\/[\w\d\.\-:]*)\/?/g
.exec(window.location.href)[1];
}
}

/**
* @desc Class exposing `/cealloga` service mappings.
* @since 0.1.0
*/
class Cealloga {
constructor(_client) {
this._client = _client;
}

exec(name, body, callback) {
let endpoint, host = this._client.host;

/* istanbul ignore if */
if (typeof arguments[0] === 'object') {
endpoint = arguments[0].endpoint;
} else {
endpoint = `${endpoints.ceallogaProd}/${name}`;
}

request(`${host}${endpoint}`, 'POST', body, callback);
}

_test(id, body, callback) {
let endpoint, host = this._client.host;

/* istanbul ignore if */
if (typeof arguments[0] === 'object') {
endpoint = arguments[0].endpoint;
} else {
endpoint = `${endpoints.ceallogaDev}/${id}`;
}

request(`${host}${endpoint}`, 'POST', body, callback);
}
}

/**
* @desc Class exposing `/code` service mappings.
* @since 0.1.0
*/
class Code {
constructor(_client) {
this._client = _client;
}

list(query, callback) {
let params = queryString(query),
endpoint = `${endpoints.codeList}?${params}`,
host = this._client.host;

request(`${host}${endpoint}`, 'GET', null, callback);
}

publish(id, callback) {
let endpoint = `${endpoints.codePublish}/${id}`,
host = this._client.host;

request(`${host}${endpoint}`, 'GET', null, callback);
}

record(id, callback) {
let endpoint = `${endpoints.codeRecord}/${id}`,
host = this._client.host;

request(`${host}${endpoint}`, 'GET', null, callback);
}

unpublish(name, callback) {
let endpoint = `${endpoints.codeUnpublish}/${name}`,
host = this._client.host;

request(`${host}${endpoint}`, 'GET', null, callback);
}

validate(body, callback) {
let endpoint = `${endpoints.codeValidate}`,
host = this._client.host;

request(`${host}${endpoint}`, 'POST', body, callback);
}
}

/**
* @desc Creates and returns new instance of Ceallóga api client with options
* provided.
* @param {Object} options Options for `ApiClient` constructor.
* @returns {ApiClient}
*/
export function api(options) {
options = options || {};

if (options.Headers) global.Headers = options.Headers;

return new ApiClient(options);
}
42 changes: 42 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "cealloga-client-es",
"version": "0.1.0",
"description": "A cealloga client for ECMAScript",
"main": "index.js",
"scripts": {
"coverage": "nyc report --reporter=text-lcov | coveralls",
"test": "nyc mocha --exit --compilers js:babel-register"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ancamcheachta/cealloga-client-es.git"
},
"keywords": [
"cealloga",
"rest",
"api",
"microservices"
],
"author": "An Camchéachta <ancamcheachta@protonmail.com>",
"license": "GPL-3.0",
"bugs": {
"url": "https://github.com/ancamcheachta/cealloga-client-es/issues"
},
"homepage": "https://github.com/ancamcheachta/cealloga-client-es#readme",
"devDependencies": {
"babel-core": "^6.26.0",
"babel-preset-env": "^1.6.1",
"chai": "^4.1.2",
"chai-fetch-mock": "^1.0.1",
"coveralls": "^3.0.0",
"fetch-mock": "^5.1.0",
"mocha": "^5.0.1",
"mocha-lcov-reporter": "^1.3.0",
"nyc": "^11.4.1"
},
"babel": {
"presets": [
"env"
]
}
}
Loading

0 comments on commit a52cdc1

Please sign in to comment.