Comparing version 1.2.0 to 1.3.0
# Changelog | ||
## 1.3.0 | ||
### What's new | ||
- The `baseURL` configuration option now defaults to `/`. | ||
- The `baseURL` configuration option is no longer a required option. | ||
- `::resource` returns a namespaced version of the API. | ||
- `::resource` accepts function as a third argument. This function is | ||
invoked with a namespaced version of the Gangway instance that | ||
operates under the provided key. | ||
This version adds namespacing to Gangway. The following is now | ||
possible: | ||
```javascript | ||
var API = Gangway() | ||
// This will create CRUD routes for `/users` and `/users/{user_id}/articles` | ||
API.resource('users', {}, function (users) { | ||
users.resource('articles') | ||
}) | ||
``` | ||
### Upgrading | ||
Those chaining off of `::resource` should update their code to reflect | ||
the change in the returned value. This returned value is a namespaced | ||
version of the Gangway instance that operates on the key given as the | ||
first argument. | ||
#### Old | ||
```javascript | ||
var API = Gangway() | ||
API.resource('users') | ||
.resource('posts') | ||
``` | ||
#### New | ||
```javascript | ||
var API = Gangway() | ||
API.resource('users') | ||
API.resource('posts') | ||
``` | ||
## 1.2.0 | ||
@@ -4,0 +52,0 @@ |
@@ -24,1 +24,98 @@ # Gangway Documentation | ||
``` | ||
### `.route(routes)` | ||
New endpoints can be added to Gangway via `.route`: | ||
```javascript | ||
var Gangway = require('gangway') | ||
var API = Gangway() | ||
API.route({ | ||
users: { | ||
read: { | ||
path: '/users/{:id?}' | ||
} | ||
}, | ||
comments: { | ||
read: { | ||
path: '/comments/{:id?}' | ||
} | ||
} | ||
}) | ||
``` | ||
This will create functions to read users and comments at | ||
`API.users.read` and `API.comments.read`. | ||
### `.resource(name, options, nest)` | ||
`.resource` is used to create endpoints in bulk. For example: | ||
```javascript | ||
var Gangway = require('gangway') | ||
var API = Gangway() | ||
API.resource('users') | ||
``` | ||
This is equivalent to executing `route` to create a `create`, `read`, | ||
`update`, and `delete` route under `users`. | ||
#### Extending default options | ||
Any options you provide as the second argument will extend the default | ||
values resource pumps in as options for these routes. For example: | ||
```javascript | ||
var Gangway = require('gangway') | ||
var API = Gangway() | ||
API.resource('users', { | ||
query: { | ||
comments: true | ||
} | ||
}) | ||
``` | ||
Would add a `?comments=true` query string to the end of every route's | ||
URL. | ||
#### Working under a namespace | ||
Finally, the last argument of `resource` is a function. Gangway will | ||
invoke this function with a version of the API that operates under the | ||
given namespace: | ||
```javascript | ||
var Gangway = require('gangway') | ||
var API = Gangway() | ||
API.resource('users', {}, function (users) { | ||
users.resource('articles') | ||
}) | ||
``` | ||
In the example above, the API will contain standard CRUD routes for | ||
users _and_ articles under `/users/{user_id}/articles`. | ||
### `.namespace(resourceName)` | ||
Namespace is used by `.resource` to create a version of the API that | ||
operates at a given path: | ||
```javascript | ||
var Gangway = require('gangway') | ||
var API = Gangway() | ||
var users = API.namespace('users') | ||
``` | ||
All invocations under users will operate within the users | ||
namespace. This means `users.route({})` will set all URL paths to | ||
`/users/{user_id}/{providedPath}`. |
{ | ||
"name": "gangway", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"description": "A client-side API abstraction layer", | ||
"engines": { | ||
"node": ">= 0.12" | ||
}, | ||
"main": "src/api.js", | ||
@@ -19,2 +22,3 @@ "scripts": { | ||
"dependencies": { | ||
"inflected": "1.1.6", | ||
"promise": "~7.1", | ||
@@ -21,0 +25,0 @@ "superagent": "~1.7" |
@@ -16,3 +16,3 @@ # Gangway | ||
The first step is invoke Gangway with some options: | ||
### Create an instance of Gangway | ||
@@ -30,4 +30,3 @@ ```javascript | ||
With default configuration options out of the way, let's add some | ||
specific routes. | ||
### Add routes | ||
@@ -50,2 +49,4 @@ ```javascript | ||
### Add routes in bulk with `.resource` | ||
For RESTful resources, adding routes this way can become | ||
@@ -61,4 +62,6 @@ tedious. Gangway provides another method for quickly building routes | ||
From there, the Gangway instance is ready for use! | ||
### Sending requests | ||
Assuming the previous steps have been followed, Gangway is ready for use! | ||
```javascript | ||
@@ -77,3 +80,4 @@ // This will send a request to GET http://example.com/users | ||
See the available options below, or consider working through the | ||
Checkout the [./docs](./docs) folder and the available options | ||
below. Or consider working through the | ||
[Hello Gangway](./docs/guides/hello-gangway.md) guide. | ||
@@ -97,4 +101,2 @@ | ||
Additionally consider skimming through the [./docs](./docs) folder. | ||
*** | ||
@@ -101,0 +103,0 @@ |
@@ -15,3 +15,3 @@ var Mock = require('./mock') | ||
var location = url(options.baseURL, options.path, assign(options.body, options.params)) | ||
var location = url(options.baseURL, options.path, assign({}, options.body, options.params)) | ||
var message = Request(options.method, location) | ||
@@ -18,0 +18,0 @@ |
@@ -1,39 +0,54 @@ | ||
var ajax = require('./ajax') | ||
var route = require('./route') | ||
var resource = require('./resource') | ||
var url = require('./url') | ||
var ajax = require('./ajax') | ||
var assign = require('./assign') | ||
var prepare = require('./prepare') | ||
var resource = require('./resource') | ||
var route = require('./route') | ||
var url = require('./url') | ||
var segmentize = require('./segmentize') | ||
module.exports = function (config, routes) { | ||
if (!config) { | ||
throw new TypeError('Please provide a configuration object as the first argument.') | ||
function API (config, routes) { | ||
if (this instanceof API === false) { | ||
return new API(config, routes) | ||
} | ||
if ('baseURL' in config === false) { | ||
throw new TypeError('baseURL configuration option is required') | ||
} | ||
this.config = prepare(config) | ||
this.segments = [] | ||
var API = { | ||
config: config, | ||
ajax: ajax, | ||
this.route(routes) | ||
} | ||
toString: function () { | ||
return config.baseURL | ||
}, | ||
API.prototype = { | ||
ajax: ajax, | ||
resolve: function (path, params) { | ||
return url(config.baseURL, path, params) | ||
}, | ||
namespace: function (key) { | ||
// Create a clone of the current instance, overriding the segments | ||
// attribute to be one step deeper | ||
var child = Object.create(this, { | ||
segments: { value: this.segments.concat(key) } | ||
}) | ||
route: function (routes) { | ||
return route(API, routes) | ||
}, | ||
// Prevent the namespace from clobbering any existing routes. Instead, | ||
// assign those routes to the namespace as properties | ||
this[key] = key in this ? assign(child, this[key]) : child | ||
resource: function (routes, options) { | ||
return resource(API, routes, options) | ||
} | ||
return child | ||
}, | ||
toString: function () { | ||
return url.resolve(this.config.baseURL, segmentize(this.segments)) | ||
}, | ||
resolve: function (path, params) { | ||
return url(this.toString(), path, params) | ||
}, | ||
route: function (routes) { | ||
return route(this, routes) | ||
}, | ||
resource: function (routes, options, nest) { | ||
return resource(this, routes, options, nest) | ||
} | ||
} | ||
return API.route(routes) | ||
} | ||
module.exports = API |
var toArray = require('./toArray') | ||
module.exports = function assign (/* objects list */) { | ||
module.exports = function assign (initial/*... objects list */) { | ||
@@ -13,3 +13,3 @@ return toArray(arguments).reduce(function(memo, next) { | ||
return memo | ||
}, {}) | ||
}, initial || {}) | ||
} |
@@ -5,6 +5,7 @@ /** | ||
var toArray = require('./toArray') | ||
var assign = require('./assign') | ||
var assign = require('./assign') | ||
var toArray = require('./toArray') | ||
var DEFAULTS = { | ||
baseURL : '/', | ||
body : undefined, | ||
@@ -23,9 +24,7 @@ params : undefined, | ||
module.exports = function prepare (/* options list */) { | ||
var options = [ DEFAULTS ].concat(toArray(arguments)).filter(function (config) { | ||
return !!config | ||
}) | ||
var options = [ DEFAULTS ].concat(toArray(arguments)) | ||
return options.reduce(function (memo, next) { | ||
return assign(memo, next, { | ||
return next ? assign(memo, next, { | ||
body : assign(memo.body, next.body), | ||
@@ -35,4 +34,5 @@ params : assign(memo.params, next.params), | ||
headers : assign(memo.headers, next.headers) | ||
}) | ||
}) : memo | ||
}, {}) | ||
} |
var assign = require('./assign') | ||
module.exports = function resource (API, name, options) { | ||
module.exports = function resource (API, name, options, nest) { | ||
var route = {} | ||
route[name] = { | ||
create: assign(options, { | ||
create: assign({}, options, { | ||
method: 'POST', | ||
@@ -12,3 +12,3 @@ path: name | ||
read: assign(options, { | ||
read: assign({}, options, { | ||
method: 'GET', | ||
@@ -18,3 +18,3 @@ path: name + '/{id?}' | ||
update: assign(options, { | ||
update: assign({}, options, { | ||
method: 'PATCH', | ||
@@ -24,3 +24,3 @@ path: name + '/{id}' | ||
destroy: assign(options, { | ||
destroy: assign({}, options, { | ||
method: 'DELETE', | ||
@@ -31,3 +31,11 @@ path: name + '/{id}' | ||
return API.route(route) | ||
API.route(route) | ||
var child = API.namespace(name) | ||
if (nest) { | ||
nest(child) | ||
} | ||
return child | ||
} |
@@ -5,7 +5,15 @@ var parameterizeRoute = require('./parameterizeRoute') | ||
module.exports = function (base, path, params) { | ||
function resolve (base, path) { | ||
base = base.replace(trimRight, '') | ||
path = path.replace(trimLeft, '') | ||
return parameterizeRoute(base + '/' + path, params).replace(trimRight, '') | ||
return (base + '/' + path).replace(trimRight, '') | ||
} | ||
function url (base, path, params) { | ||
return resolve(parameterizeRoute(resolve(base, path), params), '') | ||
} | ||
module.exports = url | ||
module.exports.resolve = resolve |
@@ -8,20 +8,2 @@ var API = require('../src/api') | ||
it ('throws an error if not given a config', function(done) { | ||
try { | ||
API() | ||
} catch(error) { | ||
assert(error instanceof TypeError) | ||
done() | ||
} | ||
}) | ||
it ('throws an error if not given a baseURL', function(done) { | ||
try { | ||
API({}) | ||
} catch(error) { | ||
assert(error instanceof TypeError) | ||
done() | ||
} | ||
}) | ||
it ('stringifies to a given baseURL', function() { | ||
@@ -28,0 +10,0 @@ assert.equal(API({ baseURL: baseURL }).toString(), baseURL) |
@@ -66,2 +66,20 @@ var API = require('../src/api') | ||
}) | ||
context('when a namespace function is provided', function() { | ||
var api = API() | ||
it ('can create namespaced routes', function(done) { | ||
api.resource('users', {}, function (users) { | ||
assert.equal(users.create, api.users.create) | ||
done() | ||
}) | ||
}) | ||
}) | ||
it('returns a namespaced API object', function() { | ||
var api = API() | ||
var users = api.resource('users') | ||
assert.equal(users, api.users) | ||
}) | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
38582
32
669
103
3
1
+ Addedinflected@1.1.6
+ Addedinflected@1.1.6(transitive)