| var easyApi = require('../src/easyApi') | ||
| module.exports = function(port) { | ||
| var app = easyApi(); | ||
| app.getAsync('/console.log', function(objects) { | ||
| console.log.apply(console, objects) | ||
| //return objects | ||
| }) | ||
| return app.start(port) | ||
| } |
@@ -8,3 +8,3 @@ var easyApi = require('../src/easyApi') | ||
| app.get('/google-first-answer', function(searchQuery) { | ||
| app.getAsync('/google-first-answer', function(searchQuery) { | ||
| return request.get('http://google.com/search?q='+searchQuery).then(function(response ) { | ||
@@ -11,0 +11,0 @@ var matches = response.match(/<h3 class="r"><a href="([^"]+)"/); |
@@ -10,6 +10,6 @@ var easyApi = require('../src/easyApi') | ||
| app.get('/messages', function() { | ||
| app.getAsync('/messages', function() { | ||
| return messages; | ||
| }) | ||
| app.post('/messages', function(message) { | ||
| app.postAsync('/messages', function(message) { | ||
| messages.push({ | ||
@@ -20,4 +20,4 @@ date: new Date, | ||
| }) | ||
| return app.start(port) | ||
| } |
@@ -5,3 +5,3 @@ var easyApi = require('../src/easyApi') | ||
| app.get( | ||
| app.getAsync( | ||
| '/some/object/:paramA/:paramB', | ||
@@ -12,3 +12,3 @@ function(paramA, paramB) { | ||
| ) | ||
| app.post( | ||
| app.postAsync( | ||
| '/some/object', | ||
@@ -15,0 +15,0 @@ function(label, content, catName) { |
+1
-1
| { | ||
| "name": "easy-api", | ||
| "version": "0.0.7", | ||
| "version": "0.1.0", | ||
| "description": "Super easy promise-based api declaration", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
+75
-32
| # easy-api | ||
| Super easy promise-based api declaration. | ||
| - Proper promise handling | ||
| - Automatic parameter retrieval | ||
| - No required error handling | ||
| - Custom error capability | ||
|  | ||
@@ -13,6 +18,41 @@ | ||
| ## Usage | ||
| Declaring route and using handlers is super easy | ||
| Here are some examples for how you do things using easy-api, along with their express equivalent. | ||
| #### Server-side | ||
| ### Route declaration | ||
| #### GET / POST / PUT / DELETE / PATCH | ||
| easy-api | ||
| ``` | ||
| app.getAsync('/message/:id', function(id) { | ||
| return db.get(id) | ||
| }) | ||
| app.postAsync('/message/:category', function(category, message) { | ||
| return db.create(message).catch(function(e) { | ||
| e.statusCode = 418 | ||
| e.message = "I'm a Teapot" | ||
| throw e; | ||
| }) | ||
| }) | ||
| ``` | ||
| express equivalent | ||
| ``` | ||
| app.get('/message/:id', function(req, res) { | ||
| dataBase.get(req.params.id).then(function(message) { | ||
| res.end(message) | ||
| }).catch(function(e) { | ||
| res.status(500).send(e.stack) | ||
| }) | ||
| }) | ||
| app.post('/message', function(req, res) { | ||
| db.create(req.body.message).then(function(whatever) { | ||
| res.json(whatever) | ||
| })).catch(function(e) { | ||
| res.status(418).send("I'm a Teapot") | ||
| }) | ||
| }) | ||
| ``` | ||
| ### Initialization | ||
| easy-api | ||
| ``` | ||
| var easyApi = require('easy-api') | ||
@@ -22,28 +62,32 @@ | ||
| app.get( | ||
| '/some/object/:paramA/:paramB', | ||
| function(paramA, paramB) { | ||
| return doAnythingNotPromisified(paramA, paramB); | ||
| // or... | ||
| return doAnythingPromisified(paramA, paramB); | ||
| } | ||
| ) | ||
| app.post( | ||
| '/some/object', | ||
| function(label, content, catName) { | ||
| return createObjectHoweverYouWant(label, content, catName); | ||
| } | ||
| ) | ||
| // ... | ||
| // declare your routes | ||
| // ... | ||
| app.start(4567).then(function() { | ||
| console.log('Server started') | ||
| app.start(1337).then(function() { | ||
| console.log('server is running') | ||
| }) | ||
| ``` | ||
| Currently, the value resolved by the promise (or returned by the function) is returned using JSON.stringify. | ||
| express equivalent | ||
| ``` | ||
| var express = require('express') | ||
| var bodyParser = require('body-parser') | ||
| #### Client-side | ||
| var app = express(); | ||
| // ... | ||
| // declare your routes | ||
| // ... | ||
| app.listen(1337, function() { | ||
| console.log('server is running') | ||
| }) | ||
| ``` | ||
| ## Client-side (code snippet for convenience) | ||
| ##### Using [request](https://www.npmjs.com/package/request) (or [request-promise](https://www.npmjs.com/package/request-promise)) | ||
| ``` | ||
| request.get({ | ||
| url : '/some/object/valueA/valueB', | ||
| url : '/message/1', | ||
| json : true | ||
@@ -53,8 +97,6 @@ }) | ||
| request.post({ | ||
| uri: '/some/object', | ||
| uri: '/message/catSound', | ||
| json : true, | ||
| body : { | ||
| label : 'cat', | ||
| content : 'meow', | ||
| catName : 'Isis' | ||
| message : 'Meow' | ||
| } | ||
@@ -65,7 +107,5 @@ }) | ||
| ``` | ||
| request('GET', '/some/object/valueA/valueB') | ||
| request('POST', '/some/object', { | ||
| label : 'cat', | ||
| content : 'meow', | ||
| catName : 'Isis' | ||
| request('GET', '/message/1') | ||
| request('POST', '/message/catSound', { | ||
| message : 'meow' | ||
| }) | ||
@@ -97,7 +137,10 @@ | ||
| ## Tests | ||
| Code is thoroughly tested and has been written using TDD. | ||
| ``` | ||
| npm test | ||
| ``` | ||
|  | ||
| Please open issues in GitHub if you encounter any problem using this module. | ||
|  | ||
| ## Star the project if you like it :) | ||
| Thanks |
+31
-12
@@ -31,9 +31,14 @@ var express = require('express') | ||
| resolve(handler.apply(app, parameters)) | ||
| }).catch(function(e) { | ||
| console.error(e) | ||
| throw e; | ||
| }) | ||
| } | ||
| function override(originalMethod, route, handler) { | ||
| function safeStringify(object) { | ||
| try { | ||
| return JSON.stringify(object) | ||
| } catch(e) { | ||
| return JSON.stringify({}) | ||
| } | ||
| } | ||
| function promisify(originalMethod, route, handler) { | ||
| originalMethod.call(app, route, function(req, res) { | ||
@@ -43,6 +48,9 @@ if (typeof handler == 'function') { | ||
| res.set('Content-Type', 'application/json') | ||
| res.end(JSON.stringify(resolvedValue)) | ||
| res.end(safeStringify(resolvedValue)) | ||
| }).catch(function(e) { | ||
| res.set('Content-Type', 'application/json') | ||
| res.status(e.statusCode || 500).end(safeStringify(e ? (e.stack || e) : '')) | ||
| }) | ||
| } else { | ||
| res.end() | ||
| res.end(safeStringify(handler)) | ||
| } | ||
@@ -53,10 +61,21 @@ }) | ||
| app.get = function(route, method) { | ||
| return override(overridenMethods.get, route, method) | ||
| } | ||
| var methods = [ | ||
| 'GET', | ||
| 'POST', | ||
| 'PUT', | ||
| 'DELETE', | ||
| 'HEAD', | ||
| 'PATCH' | ||
| ] | ||
| var originalMethods = {}; | ||
| app.post = function(route, method) { | ||
| return override(overridenMethods.post, route, method) | ||
| } | ||
| methods.forEach(function(methodName) { | ||
| methodName = methodName.toLowerCase() | ||
| originalMethods[methodName] = app[methodName] | ||
| app[methodName + 'Async'] = function(route, method) { | ||
| return promisify(originalMethods[methodName], route, method) | ||
| } | ||
| }) | ||
| app.start = function(port) { | ||
@@ -63,0 +82,0 @@ return new Promise(function(resolve) { |
+89
-52
@@ -14,64 +14,101 @@ var request = require('supertest-as-promised') | ||
| var returnedFunction = easyApi() | ||
| expect(returnedFunction.get).to.be.a('function') | ||
| expect(returnedFunction.post).to.be.a('function') | ||
| expect(returnedFunction.getAsync).to.be.a('function') | ||
| expect(returnedFunction.postAsync).to.be.a('function') | ||
| expect(returnedFunction.start).to.be.a('function') | ||
| }) | ||
| }) | ||
| describe('get()', function() { | ||
| it('gives access to the route', function() { | ||
| return request(easyApi().get('/test')) | ||
| .get('/test') | ||
| .expect(200) | ||
| testHTTPMethod('get') | ||
| testHTTPMethod('post') | ||
| testHTTPMethod('put') | ||
| testHTTPMethod('delete') | ||
| testHTTPMethod('patch') | ||
| function testHTTPMethod(method) { | ||
| describe(method + '()', function() { | ||
| it('gives access to the route', function() { | ||
| return request(easyApi()[method+'Async']('/test')) | ||
| [method]('/test') | ||
| .expect(200) | ||
| }) | ||
| it('sends the final value resolved by the promise returned by the function passed as parameter', function() { | ||
| return request(easyApi()[method+'Async']('/test', function() { | ||
| return Promise.resolve('string !') | ||
| })) | ||
| [method]('/test') | ||
| .expect(200) | ||
| .then(function(res) { | ||
| expect(JSON.parse(res.text)).to.equal('string !') | ||
| }) | ||
| }) | ||
| it('sends the value returned by the function passed as parameter', function() { | ||
| return request(easyApi()[method+'Async']('/test', function() { | ||
| return 'string !' | ||
| })) | ||
| [method]('/test') | ||
| .expect(200) | ||
| .then(function(res) { | ||
| expect(JSON.parse(res.text)).to.equal('string !') | ||
| }) | ||
| }) | ||
| it('sends the static value passed as parameter', function() { | ||
| return request(easyApi()[method+'Async']('/test', 'string !')) | ||
| [method]('/test') | ||
| .expect(200) | ||
| .then(function(res) { | ||
| expect(JSON.parse(res.text)).to.equal('string !') | ||
| }) | ||
| }) | ||
| it('pass any parameters which name is declared in the handler signature', function() { | ||
| return request(easyApi()[method+'Async']( | ||
| '/test/:id', | ||
| function(id) { | ||
| return Promise.resolve(id) | ||
| }))[method]('/test/valueForID') | ||
| .expect(200) | ||
| .then(function(res) { | ||
| expect(JSON.parse(res.text)).to.equal('valueForID') | ||
| }) | ||
| }) | ||
| it('gives access to the value send by the request to the function passed as parameter', function() { | ||
| var stub = sinon.stub(), | ||
| handler = function(id, parameter, otherParameter) { | ||
| stub.apply(stub, arguments); | ||
| }; | ||
| var app = easyApi()[method+'Async']('/test/:id', handler) | ||
| return request(app) | ||
| [method]('/test/42') | ||
| .send({ | ||
| otherParameter: 'valueForOtherParameter', | ||
| parameter: 'valueForParameter' | ||
| }) | ||
| .expect(200) | ||
| .then(function(res) { | ||
| expect(stub.withArgs('42', 'valueForParameter', 'valueForOtherParameter').calledOnce).to.be.true | ||
| }) | ||
| }) | ||
| it('should handle error like a boss', function() { | ||
| return request(easyApi()[method+'Async']('/error', function() { | ||
| return Promise.reject(new Error('no way !')) | ||
| })) | ||
| [method]('/error') | ||
| .expect(500) | ||
| .then(function(res) { | ||
| expect(JSON.parse(res.text).indexOf('no way !')).to.be.above(-1) | ||
| }) | ||
| }) | ||
| }) | ||
| it('returns the final value resolved by the promise returned by the function passed as parameter', function() { | ||
| return request(easyApi().get('/test', function() { return Promise.resolve('string !') })) | ||
| .get('/test') | ||
| .expect(200) | ||
| .then(function(res) { | ||
| expect(JSON.parse(res.text)).to.equal('string !') | ||
| }) | ||
| } | ||
| describe('start()', function() { | ||
| it('returns a promise', function() { | ||
| expect(easyApi().start(4562).then).to.be.a('function'); | ||
| }) | ||
| it('pass any parameters which name is declared in the handler signature', function() { | ||
| return request(easyApi().get( | ||
| '/test/:id', | ||
| function(id) { | ||
| return Promise.resolve(id) | ||
| }) | ||
| ).get('/test/valueForID') | ||
| .expect(200) | ||
| .then(function(res) { | ||
| expect(JSON.parse(res.text)).to.equal('valueForID') | ||
| }) | ||
| }) | ||
| }) | ||
| describe('post()', function() { | ||
| it('gives access to the route', function() { | ||
| return request(easyApi().post('/test')) | ||
| .post('/test') | ||
| .expect(200) | ||
| }) | ||
| it('gives access to the value send by the request to the function passed as parameter', function() { | ||
| var stub = sinon.stub(), | ||
| handler = function (id, parameter, otherParameter) { | ||
| stub.apply(stub, arguments); | ||
| }; | ||
| var app = easyApi().post('/test/:id', handler) | ||
| return request(app) | ||
| .post('/test/42') | ||
| .send({ | ||
| otherParameter : 'valueForOtherParameter', | ||
| parameter : 'valueForParameter' | ||
| }) | ||
| .expect(200) | ||
| .then(function(res) { | ||
| expect(stub.withArgs('42', 'valueForParameter', 'valueForOtherParameter').calledOnce).to.be.true | ||
| }) | ||
| }) | ||
| }) | ||
| describe('chaining capabilities', function() { | ||
| easyApi() | ||
| .get('/messages', function() { | ||
| .getAsync('/messages', function() { | ||
| return Promise.resolve(['lol']) | ||
| }) | ||
| .post('/messages', function(messages) { | ||
| .postAsync('/messages', function(messages) { | ||
| return Promise.resolve() | ||
@@ -78,0 +115,0 @@ }) |
+31
-1
| var expect = require('chai').expect | ||
| var sinon = require('sinon') | ||
| var request = require('request-promise') | ||
@@ -79,2 +79,32 @@ | ||
| }) | ||
| describe('distant-console-log', function() { | ||
| var log; | ||
| before(function() { | ||
| log = global.console.log; | ||
| global.console.log = sinon.stub() | ||
| }) | ||
| after(function() { | ||
| global.console.log = log | ||
| }) | ||
| it('should have a working API', function() { | ||
| var messageServer = require('../examples/distant-console-log') | ||
| var port = 5333 | ||
| var baseUrl = 'http://localhost:' + port | ||
| return messageServer(port).then(function() { | ||
| return request.get({ | ||
| uri: baseUrl + '/console.log', | ||
| json : true, | ||
| body : { | ||
| objects : ['My', 'cat', 'is', 'beautiful'] | ||
| } | ||
| }).then(function(objects) { | ||
| expect(global.console.log.withArgs('My', 'cat', 'is', 'beautiful').calledOnce).to.be.true; | ||
| global.console.log = log | ||
| }) | ||
| }) | ||
| }) | ||
| }) | ||
| }) |
18897
30.93%14
7.69%397
28.48%142
43.43%