Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added client with fetch support #2

Merged
merged 1 commit into from
Feb 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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