{"_id":"588f722cbcace50f0052ba17","user":"565f5f29de5dc50d00acfe9f","project":"565f5fa26bafd40d0030a064","version":{"_id":"588f722bbcace50f0052b9e1","project":"565f5fa26bafd40d0030a064","__v":1,"createdAt":"2017-01-30T17:04:43.410Z","releaseDate":"2017-01-30T17:04:43.410Z","categories":["588f722bbcace50f0052b9e2","588f722bbcace50f0052b9e3","588f722bbcace50f0052b9e4","588f722bbcace50f0052b9e5","588f722bbcace50f0052b9e6","588f722bbcace50f0052b9e7"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"5.3.0","version":"5.3.0"},"__v":0,"category":{"_id":"588f722bbcace50f0052b9e5","version":"588f722bbcace50f0052b9e1","__v":0,"project":"565f5fa26bafd40d0030a064","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2016-02-18T20:31:28.395Z","from_sync":false,"order":3,"slug":"sdks","title":"Client SDKs"},"parentDoc":null,"updates":["57e54b68685f7c19007fba3d","57ea8c047728c8220022bff9"],"next":{"pages":[],"description":""},"createdAt":"2016-02-18T20:56:19.619Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":1,"body":"The nanoscale.io JavaScript SDK is a lightweight SDK written with JavaScript. It can be used to connect things like web clients and Node servers to a nanoscale.io gateway. You can view the source <a href=\"https://github.com/nanoscaleio/justapis-javascript-sdk\" target=\"_blank\">here on GitHub</a>.\n\n##Dependencies\n\n* [Native Promise Only](https://github.com/getify/native-promise-only)\n* [Tiny Emitter](https://github.com/scottcorgan/tiny-emitter)\n* [xml2js](https://www.npmjs.com/package/xml2js) (when running in Node only)\n* [xmlserializer](https://www.npmjs.com/package/xmlserializer) (when running in Node only)\n\n##Features\n\n* Browser & Node.js support\n* HTTP request/response connection\n* HTTP Public Key Pinning\n* Per-request caching\n* Pausable/Resumable asynchronous request queue\n\n##Install via NPM\n\nYou can find this project on NPM <a href=\"https://www.npmjs.com/package/justapis-javascript-sdk\" target=\"_blank\">here.</a> \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"$ npm install justapis-javascript-sdk\",\n      \"language\": \"shell\",\n      \"name\": \"Install SDK via npm\"\n    }\n  ]\n}\n[/block]\n##Setup\n\nThe SDK is built with browserify. If you would like to add a single bundled file you can find it in the `dist` folder.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<script src=\\\"justapis-javascript-sdk/dist/justapis-javascript-sdk-v0.1.0.js\\\"></script>\",\n      \"language\": \"html\"\n    }\n  ]\n}\n[/block]\nIf you are using Browserify in your project you probably prefer to use `require` to load the dependency.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"var APGateway = require(\\\"justapis-javascript-sdk\\\");\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n###Creating a Gateway\n\nThe main object in the SDK is APGateway, you can think of it as an http client. To make a request to an endpoint you just need to do the following:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"var APGateway = require(\\\"justapis-javascript-sdk\\\");\\n\\nvar options = {\\n\\turl: \\\"http://my.gateway.domain.org/users\\\",\\n\\tmethod: \\\"GET\\\",\\n\\theaders: {\\n\\t\\t\\\"Foo\\\": \\\"Bar\\\"\\n\\t},\\n\\tdata: {\\n\\t\\t\\\"name\\\": \\\"john\\\"\\n\\t}\\n};\\n\\n// If you prefer objects you can do:\\nvar gw = new APGateway(options);\\n\\n// Or you can create it like this\\nvar gw = APGateway.create(options);\\n\\n// Now executing a request is as easy as\\ngw.execute().then(function(response) {\\n\\t// Response came back ok...\\n\\tconsole.log(response.data);\\n}).catch(function(error) {\\n\\t// An error occured :(\\n\\tconsole.log(error.message);\\n});\\n\\n// Also you can reuse your gateway as many times as you like.\\n// It will send the same request as before...\\ngw.execute();\\n\\n// Or you can change only the pieces that you want and keep using it...\\ngw.method(\\\"POST\\\").execute();\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n###Copying a Gateway\n\nA nice feature of gateways is that they can be copied. By copying a gateway you get all the configuration from the original, so you don't have to repeat yourself.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"var gw = new APGateway({\\n\\theaders: {\\n\\t\\t\\\"Foo\\\": \\\"Bar\\\"\\n\\t}\\n});\\n\\n// just call the copy method\\nvar gwCopy = gw.copy();\\n\\ngwCopy.headers({\\n\\t\\\"Foo\\\": \\\"Hello World!\\\"\\n});\\n\\ngw.headers(); // will return { \\\"Foo\\\": \\\"Bar\\\" }\\ngwCopy.headers(); // will return { \\\"Foo\\\": \\\"Hello World!\\\" }\",\n      \"language\": \"javascript\",\n      \"name\": \"Copy a Gateway\"\n    }\n  ]\n}\n[/block]\n##Caching requests\n\n**Note: The Caching service behaves differently in Node than in the browser**\n\nThe **APGateway** allow for request caching per request. Only responsed to GET requests are cached, and this is enabled by default.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"var gateway = new APGateway();\\ngateway.cache(false);   // Disable caching from now on...\\ngateway.execute();      // Send request without caching the response\\ngateway.cache(true)     // Enable caching from now on...\",\n      \"language\": \"javascript\",\n      \"name\": \"Request caching\"\n    }\n  ]\n}\n[/block]\nWhen using it in Node, responses will be cached in-memory only by default. In the browser however, cached responses will be saved to `localStorage` if available.\n\nSince `localStorage` is persistent, you might want to flush it at some point.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// This will only remove localStorage entries set by\\n// APGateway's request cache\\nAPGateway.RequestCache.flush();\",\n      \"language\": \"javascript\",\n      \"name\": \"Request cache flushing\"\n    }\n  ]\n}\n[/block]\nCached responses have a TTL (time to live) of 1 week (604800000 milliseconds). Any response older than that will be ignored and removed from the cache. If you would like to use a different TTL you can set it like so:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// ttl is in milliseconds\\nAPGateway.RequestCache.ttl = 60000; // set ttl to 1 minute\",\n      \"language\": \"javascript\",\n      \"name\": \"Cache expiration\"\n    }\n  ]\n}\n[/block]\n###Custom persistence\n\nIn some cases you may want to persist the cache in a different way. In the case of Node, for example, you may want to persist cached instances through a database or external service. In order to do that you can replace `APGateway.RequestCache.storage` with your own implementation. Here is a small example of how to do just that:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// The storage object MUST have the following methods\\nAPGateway.RequestCache.storage = {\\n    /**\\n     * Set key/value pair in storage\\n     *\\n     * key -> string key identifying the value\\n     * record -> an Object containing two attributes:\\n     *      'value' -> the Object being cached\\n     *      'timestamp' -> already serialized Date string\\n     *\\n     * returns -> a Promise to be resolved when set is finished (no resolve value needed)\\n     */\\n    set: function(key, record) {...},\\n\\n    /**\\n     * Get a value from storage\\n     *\\n     * key -> string identifying the value to retrieve\\n     *\\n     * returns -> a Promise that resolves with the retrieved Object\\n     */\\n    get: function(key) {...},\\n\\n    /**\\n     * Get all values in the storage. A prefix is passed that identifies the entire cache.\\n     * This prefix is prepended to every key and used to differentiate one cache instance from another.\\n     * It is only passed as a convenience, it is not required to use it internally.\\n     *\\n     * prefix -> string prefix identifying the cache\\n     *\\n     * returns -> a Promise that resolves with an Array of the retrieved objects (or empty Array if none)  \\n     */\\n    getAll: function(prefix) {...},\\n\\n    /**\\n     * Removes a single record from the storage\\n     *\\n     * key -> string key identifying the record\\n     *\\n     * returns -> a Promise that resolves when the record has been removed (no resolve value needed)\\n     */\\n    remove: function(key) {...},\\n\\n    /**\\n     * Removes all records from storage\\n     *\\n     * prefix -> Same as with 'getAll()'\\n     *\\n     * returns -> a Promise that resolves when flushing is complete (no resolve value needed)\\n     */\\n    flush: function(prefix) {...}\\n\\n};\",\n      \"language\": \"javascript\",\n      \"name\": \"Custom cache\"\n    }\n  ]\n}\n[/block]\nYou may have noticed that all the required methods to override return a Promise, this is meant as a convenience so you can easily work with async operations when persisting records. Any Promises/A+ compliant implementation can be used (or even native Promises if available), but in case you do not want to add a promise package just for this, **APGateway** uses an implementation internally that you can find in `APGateway.Promise`.\n\n\n##Async request queue\n\n**APGateway** instances use an async queue internally to send requests. This queue is shared across instances and can be paused/resumed to avoid sending further requests at any time. If your application goes offline you can pause the queue, wait for reconnection, and resume it without loosing requests.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"APGateway.Queue.pause();\\nvar gateway = new APGateway();\\ngateway\\n    .url('http://localhost:1337/resource')\\n    .execute() // This adds the request to the queue\\n    .then(function(response) { /* Got response back */ })\\n    .catch(function(error) { /* Got an error */ });\\n\\n// The queue will continue to build up until resumed\\nAPGateway.Queue.resume();\",\n      \"language\": \"javascript\",\n      \"name\": \"Request queue\"\n    }\n  ]\n}\n[/block]\nWhenever the queue is resumed it will start sending pending requests asynchronously. Because the queue can get pretty big while paused, the queue will throttle the flow of requests being sent to avoid flooding the server. The default throttle time is 300 milliseconds, but you can adjust this by doing `APGateway.Queue.throttleBy(amountInMilliseconds)`.\n\n###Persisting the queue\n\nIn some cases you might want to save the state of the queue either to `localStorage` or a database. For that purpose there's an export method on the queue you can use.\n\n**Note: The queue must be paused before calling export, otherwise an Error will be thrown**\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// Pause the queue\\nAPGateway.Queue.pause();\\n// requests will be an Array of requests\\nvar requests = APGateway.Queue.export();\\n\\n// persists requests...\",\n      \"language\": \"javascript\",\n      \"name\": \"Persist the request queue\"\n    }\n  ]\n}\n[/block]\nNow when you get your persisted requests you can just resend them.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// Get the saved requests from your storage of choice\\n\\nvar gateway = new APGateway();\\npersistedRequests.forEach(function(requestData) {\\n   // First we need to recreate the APRequest object\\n   var request = Object.create(APGateway.APRequest, requestData);\\n   gateway\\n    .sendRequest(request)\\n    .then(function(res) {\\n        // Do something else\\n    })\\n    .catch(function(error) {\\n        // There was an error\\n    });\\n});\",\n      \"language\": \"javascript\",\n      \"name\": \"Resend requests\"\n    }\n  ]\n}\n[/block]\n##APGateway instance methods\n\n###Default properties\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"url: {\\n    href: \\\"http://localhost:5000\\\",\\n    protocol: \\\"http:\\\",\\t\\t\\t\\n    hostname: \\\"localhost\\\",\\n    port: \\\"5000\\\",\\n    pathname: \\\"/\\\",\\n    search: null,\\n    hash: null\\n},\\nmethod: \\\"GET\\\",\\nsilentFail: true,\\ncache: true,\\ndataType: \\\"json\\\",\\ncontentType: \\\"application/x-www-form-urlencoded; charset=UTF-8\\\",\\ndata: {},\\nheaders: {},\\nparsers: {\\n    json: JSONParser,\\n    form: FormDataParser,\\n    xml: XMLParser\\n},\\ntransformations: {\\n    request: [ EncodeTransformation ],\\n\\tresponse: [ DecodeTransformation, CacheResponse ]\\n}\",\n      \"language\": \"javascript\",\n      \"name\": \"APGateway properties\"\n    }\n  ]\n}\n[/block]\n###Methods\n\n**.url( *url* )**\n\n* *url* -> **string**\n\t* If *url* is undefined the method will act as a getter, else it will set the value and return `this`.\n\nReturns the current url or the APGateway instance for quick chaining\n\n**.method( *method* )**\n\n* *method* -> **string**\n\t* Accepted values \"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"\n\t* If *method* is undefined the method will act as a getter, else it will set the value and return `this`.\n\nReturns the current http method or the APGateway instance for quick chaining\n\n**.data( *data* )**\n\n* *data* -> **object**\n\t* If *data* is undefined the method will act as a getter, else it will set the value and return `this`.\n\nReturns the current request data or the APGateway instance for quick chaining\n\n**.dataType( *dataType* )**\n\n* *dataType* -> **string**\n\t* If *dataType* is undefined the method will act as a getter, else it will set the value and return `this`.\n\t* \"json\" and \"xml\" dataTypes are parsed automatically, any other dataType will be returned as a string.\n\nReturns the current response data type or the APGateway instance for quick chaining\n\n**.contentType( *contentType* )**\n\n* *contentType* -> **string**\n\t* If *contentType* is undefined the method will act as a getter, else it will set the value and return `this`.\n\nReturns the current content type or the APGateway instance for quick chaining\n\n**.headers( *headers* )**\n\n* *headers* -> **object**\n\t* The key-value pairs in *headers* will be appended to the current ones.\n\t* If *headers* is undefined the method will act as a getter, else it will set the value and return `this`.\n\nReturns the current headers or the APGateway instance for quick chaining\n\n**.withCredentials( *withCredentials* )**\n\nEnabling `withCredentials` will cause any cookies to be included in the request to the server. The server needs to be configured to enable credentials as well by adding `Access-Control-Allow-Credentials: true` as a response header.\n\n* *withCredentials* -> **boolean**\n\t* Default value: `false`\n\t* If *withCredentials* is undefined the method will act as a getter, else it will set the value and return `this`.\n\nReturns the current value of withCredentials or the APGateway instance for quick chaining\n\n**.silentFail( *silent* )**\n\nWhen a request is not successful **APGateway** will throw an error. Setting *silentFail* to `true` will cause the gateway to ignore those errors.\n\n* *silent* -> **boolean**\n\t* Default value: `true`\n\t* If *silent* is undefined the method will act as a getter, else it will set the value and return `this`.\n\nReturns the current value of silentFail or the APGateway instance for quick chaining\n\n**.cache( *active* )**\n\n* *active* -> **boolean**\n\t* Default value: `true`\n\t* If *active* is undefined the method will act as a getter, else it will set the value and return `this`.\n\nReturns the current value of cache or the APGateway instance for quick chaining\n\n**.copy()**\n\nReturns a shallow copy of the APGateway instance.\n\n**.requestTransformations( *transformations* )**\n\n* *transformations* -> **Function[]**\n\t* If undefined the method will act as a getter, else it will set the value and return `this`.\n\t* Array of functions to transform the request configuration **before** it is sent to the server\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"gw.requestTransformations([\\n\\t\\t\\t// transformations must ALWAYS return \\\"request\\\"\\n\\t\\t\\t// in order for the entire chain to work properly\\n\\t\\t\\tfunction(request) {...},\\n\\t\\t\\tfunction(request) {...}\\t\\t\\n\\t\\t]);\",\n      \"language\": \"javascript\",\n      \"name\": \"Request transformations\"\n    }\n  ]\n}\n[/block]\nReturns the current request transformations or the APGateway instance for quick chaining\n\n**.responseTransformations( *transformations* )**\n\n* *transformations* -> **Function[]**\n\t* If undefined the method will act as a getter, else it will set the value and return `this`.\n\t* Array of functions to transform the response object **after** it returns from the server\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"gw.responseTransformations([\\n\\t\\t\\t// transformations must ALWAYS return \\\"response\\\"\\n\\t\\t\\t// in order for the entire chain to work properly\\n\\t\\t\\tfunction(response) {...},\\n\\t\\t\\tfunction(response) {...}\\t\\t\\n\\t\\t]);\",\n      \"language\": \"javascript\",\n      \"name\": \"Response transformations\"\n    }\n  ]\n}\n[/block]\nReturns the current response transformations or the APGateway instance for quick chaining\n\n**.addRequestTransformation( *transformation* )**\n\n* *transformation* -> **Function**\n\t* Adds the transformation at the end of the request transformation chain\n\nReturns the APGateway instance for quick chaining\n\n**.addResponseTransformation( *transformation* )**\n\n* *transformation* -> **Function**\n\t* Adds the transformation at the end of the response transformation chain\n\nReturns the APGateway instance for quick chaining\n\n**.hpkp( *options* )**\n\n* *options* -> **Object**\n\n    **Should contain:**\n\n    * *sha256s* (required) -> **string[]**\n        * Array of **two** encoded public key information hashes. One is actually used, the other is kept as backup.\n    * *maxAge* (required) -> **number**\n        * The time in seconds that the pinned key will be remembered for.\n    * *includeSubdomains* (optional) -> **boolean**\n        * Applies the pinned key to subdomains also.\n    * *reportOnly* (optional) -> **boolean**\n        * Specifies if pin validation failures should be reported to the given URL (if true *reportUri* must be present as well).\n    * *reportUri* (optional) -> **string**\n        * URL to send pin validation failure reports to.\n\n* Sets up [HTTP Public Key Pinning](https://developer.mozilla.org/en/docs/Web/Security/Public_Key_Pinning) for the **APGateway** instance.\n\n**.execute()**\n\n* Executes a request with the current configuration\n\nReturns a Promise\n\n##Framework integration\n\n###React\n\nThe SDK will work with React.js out of the box since its plain JavaScript.\n\n###Angular\n\nIntegrating with Angular.js is not a problem, here is an example of how you would use it.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"angular.module('MyModule')\\n\\t.controller('MyModuleController', ['$scope', function($scope) {\\n\\t\\t// Declare a default message to show\\n\\t\\t$scope.message = \\\"Default message\\\";\\n\\t\\t// Create the gateway as usual...\\n\\t\\tvar gateway = new APGateway();\\n\\n\\t\\tgateway\\n\\t\\t.url('http://my.service/message')\\n\\t\\t.execute()\\n\\t\\t.then(function(response) {\\n\\t\\t\\t// Keep in mind, when updating the $scope, to use $apply\\n\\t\\t\\t//   so angular is made aware of the change\\n\\t\\t\\t$scope.$apply(function() {\\n\\t\\t\\t\\t$scope.message = response.data;\\n\\t\\t\\t});\\n\\t\\t});\\n\\n\\n\\t});\",\n      \"language\": \"javascript\",\n      \"name\": \"Angular usage\"\n    }\n  ]\n}\n[/block]\n###Ember\n\nLike React or Angular, there is no restriction to use APGateway in an Ember application. If you're using Ember Data however you might want to integrate APGateway so you can load Models from it.\n\n####Ember Data\n\nIn order to integrate with Ember Data you will want to create an [Adapter](http://emberjs.com/api/data/classes/DS.Adapter.html).\n\nThis example code shows the basic principle of how to integrate the two.\n\n**NOTE**: For simplicity's sake the example only shows implementations of `findRecord` and `createRecord` but when extending `DS.Adapter` you **must** implement the other methods too.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// url of your endpoint\\nvar URL = \\\"http://localhost:5000/todos\\\";\\nvar gateway = new APGateway();\\n\\n// This helper will make sure that the response of the gateway runs\\n// inside Ember's run loop.\\nfunction runRequestToGateway(gateway) {\\n\\treturn Ember.RSVP.Promise(function(resolve, reject) {\\n\\t\\tgateway\\n\\t\\t.execute()\\n\\t\\t.then(function(response) {\\n\\t\\t\\tEmber.run(null, resolve, response.data);\\n\\t\\t})\\n\\t\\t.catch(function(error) {\\n\\t\\t\\tEmber.run(null, reject, error);\\n\\t\\t});\\n\\t});\\n}\\n\\n// Register an ApplicationAdapter that uses APGateway internally...\\nTodos.ApplicationAdapter = DS.Adapter.extend({\\n\\n\\tfindRecord: function(store, type, id, snapshot) {\\n\\t\\tgateway\\n\\t\\t.method(\\\"GET\\\")\\n\\t\\t.url(URL + \\\"/\\\" + id)\\n\\t\\t.silentFail(false);\\n\\n\\t\\treturn runRequestToGateway(gateway);\\n\\t},\\n\\n\\tcreateRecord: function(store, type, snapshot) {\\n\\t\\tvar data = this.serialize(snapshot, { includeId: true });\\n\\n\\t\\tgateway\\n\\t\\t.url(URL)\\n\\t\\t.method(\\\"POST\\\")\\n\\t\\t.data(data)\\n\\t\\t.silentFail(false);\\n\\n\\t\\treturn runRequestToGateway(gateway);\\n\\t},\\n\\n\\tupdateRecord: function(store, type, snapshot) {...},\\n\\n\\tdeleteRecord: function(store, type, snapshot) {...},\\n\\n\\tfindAll: function(store, type, sinceToken, snapshotRecordArray) {...},\\n\\n\\tquery: function(store, type, query, recordArray) {...}\\n});\",\n      \"language\": \"javascript\",\n      \"name\": \"Ember Data usage\"\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"javascript","type":"basic","title":"JavaScript"}
The nanoscale.io JavaScript SDK is a lightweight SDK written with JavaScript. It can be used to connect things like web clients and Node servers to a nanoscale.io gateway. You can view the source <a href="https://github.com/nanoscaleio/justapis-javascript-sdk" target="_blank">here on GitHub</a>. ##Dependencies * [Native Promise Only](https://github.com/getify/native-promise-only) * [Tiny Emitter](https://github.com/scottcorgan/tiny-emitter) * [xml2js](https://www.npmjs.com/package/xml2js) (when running in Node only) * [xmlserializer](https://www.npmjs.com/package/xmlserializer) (when running in Node only) ##Features * Browser & Node.js support * HTTP request/response connection * HTTP Public Key Pinning * Per-request caching * Pausable/Resumable asynchronous request queue ##Install via NPM You can find this project on NPM <a href="https://www.npmjs.com/package/justapis-javascript-sdk" target="_blank">here.</a> [block:code] { "codes": [ { "code": "$ npm install justapis-javascript-sdk", "language": "shell", "name": "Install SDK via npm" } ] } [/block] ##Setup The SDK is built with browserify. If you would like to add a single bundled file you can find it in the `dist` folder. [block:code] { "codes": [ { "code": "<script src=\"justapis-javascript-sdk/dist/justapis-javascript-sdk-v0.1.0.js\"></script>", "language": "html" } ] } [/block] If you are using Browserify in your project you probably prefer to use `require` to load the dependency. [block:code] { "codes": [ { "code": "var APGateway = require(\"justapis-javascript-sdk\");", "language": "javascript" } ] } [/block] ###Creating a Gateway The main object in the SDK is APGateway, you can think of it as an http client. To make a request to an endpoint you just need to do the following: [block:code] { "codes": [ { "code": "var APGateway = require(\"justapis-javascript-sdk\");\n\nvar options = {\n\turl: \"http://my.gateway.domain.org/users\",\n\tmethod: \"GET\",\n\theaders: {\n\t\t\"Foo\": \"Bar\"\n\t},\n\tdata: {\n\t\t\"name\": \"john\"\n\t}\n};\n\n// If you prefer objects you can do:\nvar gw = new APGateway(options);\n\n// Or you can create it like this\nvar gw = APGateway.create(options);\n\n// Now executing a request is as easy as\ngw.execute().then(function(response) {\n\t// Response came back ok...\n\tconsole.log(response.data);\n}).catch(function(error) {\n\t// An error occured :(\n\tconsole.log(error.message);\n});\n\n// Also you can reuse your gateway as many times as you like.\n// It will send the same request as before...\ngw.execute();\n\n// Or you can change only the pieces that you want and keep using it...\ngw.method(\"POST\").execute();", "language": "javascript" } ] } [/block] ###Copying a Gateway A nice feature of gateways is that they can be copied. By copying a gateway you get all the configuration from the original, so you don't have to repeat yourself. [block:code] { "codes": [ { "code": "var gw = new APGateway({\n\theaders: {\n\t\t\"Foo\": \"Bar\"\n\t}\n});\n\n// just call the copy method\nvar gwCopy = gw.copy();\n\ngwCopy.headers({\n\t\"Foo\": \"Hello World!\"\n});\n\ngw.headers(); // will return { \"Foo\": \"Bar\" }\ngwCopy.headers(); // will return { \"Foo\": \"Hello World!\" }", "language": "javascript", "name": "Copy a Gateway" } ] } [/block] ##Caching requests **Note: The Caching service behaves differently in Node than in the browser** The **APGateway** allow for request caching per request. Only responsed to GET requests are cached, and this is enabled by default. [block:code] { "codes": [ { "code": "var gateway = new APGateway();\ngateway.cache(false); // Disable caching from now on...\ngateway.execute(); // Send request without caching the response\ngateway.cache(true) // Enable caching from now on...", "language": "javascript", "name": "Request caching" } ] } [/block] When using it in Node, responses will be cached in-memory only by default. In the browser however, cached responses will be saved to `localStorage` if available. Since `localStorage` is persistent, you might want to flush it at some point. [block:code] { "codes": [ { "code": "// This will only remove localStorage entries set by\n// APGateway's request cache\nAPGateway.RequestCache.flush();", "language": "javascript", "name": "Request cache flushing" } ] } [/block] Cached responses have a TTL (time to live) of 1 week (604800000 milliseconds). Any response older than that will be ignored and removed from the cache. If you would like to use a different TTL you can set it like so: [block:code] { "codes": [ { "code": "// ttl is in milliseconds\nAPGateway.RequestCache.ttl = 60000; // set ttl to 1 minute", "language": "javascript", "name": "Cache expiration" } ] } [/block] ###Custom persistence In some cases you may want to persist the cache in a different way. In the case of Node, for example, you may want to persist cached instances through a database or external service. In order to do that you can replace `APGateway.RequestCache.storage` with your own implementation. Here is a small example of how to do just that: [block:code] { "codes": [ { "code": "// The storage object MUST have the following methods\nAPGateway.RequestCache.storage = {\n /**\n * Set key/value pair in storage\n *\n * key -> string key identifying the value\n * record -> an Object containing two attributes:\n * 'value' -> the Object being cached\n * 'timestamp' -> already serialized Date string\n *\n * returns -> a Promise to be resolved when set is finished (no resolve value needed)\n */\n set: function(key, record) {...},\n\n /**\n * Get a value from storage\n *\n * key -> string identifying the value to retrieve\n *\n * returns -> a Promise that resolves with the retrieved Object\n */\n get: function(key) {...},\n\n /**\n * Get all values in the storage. A prefix is passed that identifies the entire cache.\n * This prefix is prepended to every key and used to differentiate one cache instance from another.\n * It is only passed as a convenience, it is not required to use it internally.\n *\n * prefix -> string prefix identifying the cache\n *\n * returns -> a Promise that resolves with an Array of the retrieved objects (or empty Array if none) \n */\n getAll: function(prefix) {...},\n\n /**\n * Removes a single record from the storage\n *\n * key -> string key identifying the record\n *\n * returns -> a Promise that resolves when the record has been removed (no resolve value needed)\n */\n remove: function(key) {...},\n\n /**\n * Removes all records from storage\n *\n * prefix -> Same as with 'getAll()'\n *\n * returns -> a Promise that resolves when flushing is complete (no resolve value needed)\n */\n flush: function(prefix) {...}\n\n};", "language": "javascript", "name": "Custom cache" } ] } [/block] You may have noticed that all the required methods to override return a Promise, this is meant as a convenience so you can easily work with async operations when persisting records. Any Promises/A+ compliant implementation can be used (or even native Promises if available), but in case you do not want to add a promise package just for this, **APGateway** uses an implementation internally that you can find in `APGateway.Promise`. ##Async request queue **APGateway** instances use an async queue internally to send requests. This queue is shared across instances and can be paused/resumed to avoid sending further requests at any time. If your application goes offline you can pause the queue, wait for reconnection, and resume it without loosing requests. [block:code] { "codes": [ { "code": "APGateway.Queue.pause();\nvar gateway = new APGateway();\ngateway\n .url('http://localhost:1337/resource')\n .execute() // This adds the request to the queue\n .then(function(response) { /* Got response back */ })\n .catch(function(error) { /* Got an error */ });\n\n// The queue will continue to build up until resumed\nAPGateway.Queue.resume();", "language": "javascript", "name": "Request queue" } ] } [/block] Whenever the queue is resumed it will start sending pending requests asynchronously. Because the queue can get pretty big while paused, the queue will throttle the flow of requests being sent to avoid flooding the server. The default throttle time is 300 milliseconds, but you can adjust this by doing `APGateway.Queue.throttleBy(amountInMilliseconds)`. ###Persisting the queue In some cases you might want to save the state of the queue either to `localStorage` or a database. For that purpose there's an export method on the queue you can use. **Note: The queue must be paused before calling export, otherwise an Error will be thrown** [block:code] { "codes": [ { "code": "// Pause the queue\nAPGateway.Queue.pause();\n// requests will be an Array of requests\nvar requests = APGateway.Queue.export();\n\n// persists requests...", "language": "javascript", "name": "Persist the request queue" } ] } [/block] Now when you get your persisted requests you can just resend them. [block:code] { "codes": [ { "code": "// Get the saved requests from your storage of choice\n\nvar gateway = new APGateway();\npersistedRequests.forEach(function(requestData) {\n // First we need to recreate the APRequest object\n var request = Object.create(APGateway.APRequest, requestData);\n gateway\n .sendRequest(request)\n .then(function(res) {\n // Do something else\n })\n .catch(function(error) {\n // There was an error\n });\n});", "language": "javascript", "name": "Resend requests" } ] } [/block] ##APGateway instance methods ###Default properties [block:code] { "codes": [ { "code": "url: {\n href: \"http://localhost:5000\",\n protocol: \"http:\",\t\t\t\n hostname: \"localhost\",\n port: \"5000\",\n pathname: \"/\",\n search: null,\n hash: null\n},\nmethod: \"GET\",\nsilentFail: true,\ncache: true,\ndataType: \"json\",\ncontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\ndata: {},\nheaders: {},\nparsers: {\n json: JSONParser,\n form: FormDataParser,\n xml: XMLParser\n},\ntransformations: {\n request: [ EncodeTransformation ],\n\tresponse: [ DecodeTransformation, CacheResponse ]\n}", "language": "javascript", "name": "APGateway properties" } ] } [/block] ###Methods **.url( *url* )** * *url* -> **string** * If *url* is undefined the method will act as a getter, else it will set the value and return `this`. Returns the current url or the APGateway instance for quick chaining **.method( *method* )** * *method* -> **string** * Accepted values "GET", "POST", "PUT", "PATCH", "DELETE" * If *method* is undefined the method will act as a getter, else it will set the value and return `this`. Returns the current http method or the APGateway instance for quick chaining **.data( *data* )** * *data* -> **object** * If *data* is undefined the method will act as a getter, else it will set the value and return `this`. Returns the current request data or the APGateway instance for quick chaining **.dataType( *dataType* )** * *dataType* -> **string** * If *dataType* is undefined the method will act as a getter, else it will set the value and return `this`. * "json" and "xml" dataTypes are parsed automatically, any other dataType will be returned as a string. Returns the current response data type or the APGateway instance for quick chaining **.contentType( *contentType* )** * *contentType* -> **string** * If *contentType* is undefined the method will act as a getter, else it will set the value and return `this`. Returns the current content type or the APGateway instance for quick chaining **.headers( *headers* )** * *headers* -> **object** * The key-value pairs in *headers* will be appended to the current ones. * If *headers* is undefined the method will act as a getter, else it will set the value and return `this`. Returns the current headers or the APGateway instance for quick chaining **.withCredentials( *withCredentials* )** Enabling `withCredentials` will cause any cookies to be included in the request to the server. The server needs to be configured to enable credentials as well by adding `Access-Control-Allow-Credentials: true` as a response header. * *withCredentials* -> **boolean** * Default value: `false` * If *withCredentials* is undefined the method will act as a getter, else it will set the value and return `this`. Returns the current value of withCredentials or the APGateway instance for quick chaining **.silentFail( *silent* )** When a request is not successful **APGateway** will throw an error. Setting *silentFail* to `true` will cause the gateway to ignore those errors. * *silent* -> **boolean** * Default value: `true` * If *silent* is undefined the method will act as a getter, else it will set the value and return `this`. Returns the current value of silentFail or the APGateway instance for quick chaining **.cache( *active* )** * *active* -> **boolean** * Default value: `true` * If *active* is undefined the method will act as a getter, else it will set the value and return `this`. Returns the current value of cache or the APGateway instance for quick chaining **.copy()** Returns a shallow copy of the APGateway instance. **.requestTransformations( *transformations* )** * *transformations* -> **Function[]** * If undefined the method will act as a getter, else it will set the value and return `this`. * Array of functions to transform the request configuration **before** it is sent to the server [block:code] { "codes": [ { "code": "gw.requestTransformations([\n\t\t\t// transformations must ALWAYS return \"request\"\n\t\t\t// in order for the entire chain to work properly\n\t\t\tfunction(request) {...},\n\t\t\tfunction(request) {...}\t\t\n\t\t]);", "language": "javascript", "name": "Request transformations" } ] } [/block] Returns the current request transformations or the APGateway instance for quick chaining **.responseTransformations( *transformations* )** * *transformations* -> **Function[]** * If undefined the method will act as a getter, else it will set the value and return `this`. * Array of functions to transform the response object **after** it returns from the server [block:code] { "codes": [ { "code": "gw.responseTransformations([\n\t\t\t// transformations must ALWAYS return \"response\"\n\t\t\t// in order for the entire chain to work properly\n\t\t\tfunction(response) {...},\n\t\t\tfunction(response) {...}\t\t\n\t\t]);", "language": "javascript", "name": "Response transformations" } ] } [/block] Returns the current response transformations or the APGateway instance for quick chaining **.addRequestTransformation( *transformation* )** * *transformation* -> **Function** * Adds the transformation at the end of the request transformation chain Returns the APGateway instance for quick chaining **.addResponseTransformation( *transformation* )** * *transformation* -> **Function** * Adds the transformation at the end of the response transformation chain Returns the APGateway instance for quick chaining **.hpkp( *options* )** * *options* -> **Object** **Should contain:** * *sha256s* (required) -> **string[]** * Array of **two** encoded public key information hashes. One is actually used, the other is kept as backup. * *maxAge* (required) -> **number** * The time in seconds that the pinned key will be remembered for. * *includeSubdomains* (optional) -> **boolean** * Applies the pinned key to subdomains also. * *reportOnly* (optional) -> **boolean** * Specifies if pin validation failures should be reported to the given URL (if true *reportUri* must be present as well). * *reportUri* (optional) -> **string** * URL to send pin validation failure reports to. * Sets up [HTTP Public Key Pinning](https://developer.mozilla.org/en/docs/Web/Security/Public_Key_Pinning) for the **APGateway** instance. **.execute()** * Executes a request with the current configuration Returns a Promise ##Framework integration ###React The SDK will work with React.js out of the box since its plain JavaScript. ###Angular Integrating with Angular.js is not a problem, here is an example of how you would use it. [block:code] { "codes": [ { "code": "angular.module('MyModule')\n\t.controller('MyModuleController', ['$scope', function($scope) {\n\t\t// Declare a default message to show\n\t\t$scope.message = \"Default message\";\n\t\t// Create the gateway as usual...\n\t\tvar gateway = new APGateway();\n\n\t\tgateway\n\t\t.url('http://my.service/message')\n\t\t.execute()\n\t\t.then(function(response) {\n\t\t\t// Keep in mind, when updating the $scope, to use $apply\n\t\t\t// so angular is made aware of the change\n\t\t\t$scope.$apply(function() {\n\t\t\t\t$scope.message = response.data;\n\t\t\t});\n\t\t});\n\n\n\t});", "language": "javascript", "name": "Angular usage" } ] } [/block] ###Ember Like React or Angular, there is no restriction to use APGateway in an Ember application. If you're using Ember Data however you might want to integrate APGateway so you can load Models from it. ####Ember Data In order to integrate with Ember Data you will want to create an [Adapter](http://emberjs.com/api/data/classes/DS.Adapter.html). This example code shows the basic principle of how to integrate the two. **NOTE**: For simplicity's sake the example only shows implementations of `findRecord` and `createRecord` but when extending `DS.Adapter` you **must** implement the other methods too. [block:code] { "codes": [ { "code": "// url of your endpoint\nvar URL = \"http://localhost:5000/todos\";\nvar gateway = new APGateway();\n\n// This helper will make sure that the response of the gateway runs\n// inside Ember's run loop.\nfunction runRequestToGateway(gateway) {\n\treturn Ember.RSVP.Promise(function(resolve, reject) {\n\t\tgateway\n\t\t.execute()\n\t\t.then(function(response) {\n\t\t\tEmber.run(null, resolve, response.data);\n\t\t})\n\t\t.catch(function(error) {\n\t\t\tEmber.run(null, reject, error);\n\t\t});\n\t});\n}\n\n// Register an ApplicationAdapter that uses APGateway internally...\nTodos.ApplicationAdapter = DS.Adapter.extend({\n\n\tfindRecord: function(store, type, id, snapshot) {\n\t\tgateway\n\t\t.method(\"GET\")\n\t\t.url(URL + \"/\" + id)\n\t\t.silentFail(false);\n\n\t\treturn runRequestToGateway(gateway);\n\t},\n\n\tcreateRecord: function(store, type, snapshot) {\n\t\tvar data = this.serialize(snapshot, { includeId: true });\n\n\t\tgateway\n\t\t.url(URL)\n\t\t.method(\"POST\")\n\t\t.data(data)\n\t\t.silentFail(false);\n\n\t\treturn runRequestToGateway(gateway);\n\t},\n\n\tupdateRecord: function(store, type, snapshot) {...},\n\n\tdeleteRecord: function(store, type, snapshot) {...},\n\n\tfindAll: function(store, type, sinceToken, snapshotRecordArray) {...},\n\n\tquery: function(store, type, query, recordArray) {...}\n});", "language": "javascript", "name": "Ember Data usage" } ] } [/block]