Permalink
Browse files

added text json and html shortcuts

  • Loading branch information...
1 parent ce325b0 commit 937e17abde930842ae2dcfb0fd0807cc940ae74f @twilson63 committed Apr 28, 2012
Showing with 258 additions and 67 deletions.
  1. +31 −35 index.js
  2. +4 −0 lib/log.js
  3. +7 −0 lib/mime.js
  4. +25 −0 lib/parse.js
  5. +7 −0 lib/resource.js
  6. +1 −1 package.json
  7. +40 −14 readme.md
  8. +0 −16 test/basic-request.coffee
  9. +0 −1 test/mocha.opts
  10. +74 −0 test/resource-test.coffee
  11. +69 −0 test/routing-test.coffee
View
@@ -1,41 +1,11 @@
var pin = require('linchpin'),
url = require('url'),
http = require('http'),
- https = require('https'),
- qs = require('qs');
-
-var parseBody = function(req) {
- // exit if already parsed.
- if (req._params) return;
- req.params = null;
-
- contentType = req.headers['content-type'];
- // flag as parsed
- req._params = true;
- if (contentType === 'application/json') {
- try {
- req.params = JSON.parse(req.body);
- } catch (err) {
- pin.emit('LOG-ERROR', { type: 'ERROR', msg: err.message, date: (new Date()).toString()});
- }
- } else if (contentType === 'application/xml') {
- // TODO: convert xml to params
- } else if (contentType === 'application/x-www-form-urlencoded') {
- try {
- req.params = qs.parse(req.params)
- } catch (err) {
- pin.emit('LOG-ERROR', { type: 'ERROR', msg: err.message, date: (new Date()).toString()});
- }
- }
-}
-
-var setResource = function(path, req) {
- var pathItems = path.split('/');
- req.resource = ""; req.resourceId = "";
- if (pathItems.length > 1) { req.resource = pathItems[1]; }
- if (pathItems.length > 2) { req.resourceId = pathItems[2]; }
-
-}
+// https = require('https'),
+ parseBody = require('./lib/parse'),
+ setResource = require('./lib/resource'),
+ mime = require('./lib/mime'),
+ log = require('./lib/log');
function Apprentice() {
var self = this;
@@ -44,6 +14,32 @@ function Apprentice() {
self.httpServer.on('request', function(req, res) {
var path = url.parse(req.url).pathname, route = req.method;
+
+ res.text = function(body, statusCode) {
+ if (statusCode == null || statusCode == 'undefined') { statusCode = 200 };
+ res.writeHead(statusCode, { 'content-type': mime.text });
+ res.end(body);
+ }
+
+ res.json = function(body, statusCode) {
+ if (statusCode == null || statusCode == 'undefined') { statusCode = 200 };
+ try {
+ body = JSON.stringify(body);
+ res.writeHead(statusCode, {'content-type': mime.json });
+ res.end(body);
+ } catch (err) {
+ log('ERROR', err.message);
+ res.writeHead(statusCode, {'content-type': mime.json });
+ res.end(JSON.stringify({ error: 'BAD JSON: ' + err.message}));
+ };
+ }
+
+ res.html = function(body, statusCode) {
+ if (statusCode == null || statusCode == 'undefined') { statusCode = 200 };
+ res.writeHead(statusCode, {'content-type': mime.html });
+ res.end(body);
+ }
+
setResource(path, req);
if (path.length > 1) route += url.parse(req.url).pathname;
req.body = "";
View
@@ -0,0 +1,4 @@
+var pin = require('linchpin');
+module.exports = function(type, msg) {
+ pin.emit('LOG', { type: type, msg: msg, date: (new Date()).toString()});
+}
View
@@ -0,0 +1,7 @@
+module.exports = {
+ json: 'application/json',
+ form: 'application/x-www-form-urlencoded',
+ xml: 'application/xml',
+ text: 'text/plain',
+ html: 'text/html'
+}
View
@@ -0,0 +1,25 @@
+var mime = require(__dirname + '/mime'),
+ log = require(__dirname + '/log')
+ pin = require('linchpin'),
+ qs = require('qs');
+
+module.exports = function(req) {
+ var parse = function(parser, req) {
+ try {
+ req.params = parser.parse(req.body);
+ req._params = true;
+ } catch (err) { log('ERROR', err.message); }
+ }
+
+ if (req._params) return;
+ req.params = null;
+ contentType = req.headers['content-type'];
+ if (contentType === mime.json) {
+ parse(JSON, req);
+ } else if (contentType === mime.json) {
+ log('INFO', 'NOT IMPLEMENTED')
+ } else if (contentType === mime.form) {
+ parse(qs, req);
+ }
+ log('INFO', req.params)
+}
View
@@ -0,0 +1,7 @@
+module.exports = function(path, req) {
+ var pathItems = path.split('/');
+ req.resource = ""; req.resourceId = "";
+ if (pathItems.length > 1) { req.resource = pathItems[1]; }
+ if (pathItems.length > 2) { req.resourceId = pathItems[2]; }
+
+}
View
@@ -2,7 +2,7 @@
"author": "Tom Wilson <tom@jackhq.com>",
"name": "apprentice",
"description": "[Experimental] web library that adds some sugar to routing",
- "version": "0.2.5",
+ "version": "0.2.6",
"repository": {
"url": ""
},
View
@@ -14,26 +14,52 @@ The Apprentice makes it simple to get started creating an html and/or json web a
npm install apprentice
```
+## Dependencies
+
+* linchpin
+
+``` sh
+npm install linchpin
+```
+
# Usage
``` javascript
var app = require('apprentice'),
pin = require('linchpin');
-pin.on('GET', function(req, res) {
- res.writeHead(200, {'content-type': 'text/plain'});
- res.end('Come in to the Board Room');
-});
+pin.on('GET', function(req, res) { res.text('Come in to the Board Room'); });
+pin.on('POST/lose', function(req, res) { res.text('You\'re fired!'); });
+pin.on('PUT/win', function(req, res) { res.text('You\'re hired!'); });
+pin.on('DELETE/110%', function(req, res) { res.text('Thats Great!'); });
+
+app.httpServer.listen(3000);
+```
-pin.on('GET/lose', function(req, res) {
- res.writeHead(200, {'content-type': 'text/plain'});
- res.end('You\'re fired!');
-});
+# Features
-pin.on('GET/win', function(req, res) {
- res.writeHead(200, {'content-type': 'text/plain'});
- res.end('You\'re hired!');
-});
+## Response Macros
-app.httpServer.listen(3000);
-```
+* text (body, status=200)
+
+res.text is a shortcut to send a plain text response body back to the caller.
+
+``` javascript
+pin.on('GET', function(req, res) {res.text 'hello world');});
+```
+
+* json (body, status=200)
+
+res.json is a shortcut to send a json document to the caller.
+
+``` javascript
+pin.on('GET', function(req, res) {res.json {foo: 'bar'});});
+```
+
+* html (body, status=200)
+
+res.html is a shortcut to send a html document to the caller.
+
+``` javascript
+pin.on('GET', function(req, res) {res.html "<h1>Hello World</h1>");});
+```
View
@@ -1,16 +0,0 @@
-app = require('../')
-request = require('request')
-pin = require('linchpin')
-
-describe 'apprentice', ->
- describe 'GET /', ->
- it 'should be successful', (done) ->
- pin.on 'request/*', (req, res) ->
- console.log 'foo'
- req.writeHead 200, 'content-type': 'text/plain'
- req.end 'Hello World'
-
- app.httpServer.listen 3000
-
- request 'http://localhost:3000', (err, res, body) -> console.log body
- done()
View
@@ -1 +0,0 @@
---compilers coffee:coffee-script
View
@@ -0,0 +1,74 @@
+request = require 'request'
+assert = require 'assert'
+apprentice = require '../'
+mime = require '../lib/mime'
+pin = require 'linchpin'
+
+pin.on 'GET/foo', (req, res) -> res.json { params: req.params, resource: req.resource }
+pin.on 'POST/foo', (req, res) -> res.json { params: req.params, resource: req.resource }, 201
+pin.on 'GET/foo/*', (req, res) -> res.json { params: req.params, resource: req.resource, id: req.resourceId }
+pin.on 'PUT/foo/*', (req, res) -> res.json { params: req.params, resource: req.resource, id: req.resourceId }
+pin.on 'DELETE/foo/*', (req, res) -> res.json { resource: req.resource, id: req.resourceId }
+
+#pin.on 'LOG', (entry) -> console.log entry
+
+counter = 0
+
+# apprentice.httpServer.on 'request', (req, res) ->
+# req.connection.setTimeout = 20000
+
+apprentice.httpServer.listen 3000, ->
+ url = 'http://localhost:3000/foo'
+ errorStatus = (code) -> new Error("Status Code is not #{code}")
+ end = ->
+ counter--
+ if counter is 0 then apprentice.httpServer.close()
+
+ counter++
+
+ # route to root
+ request url, json: true, (e, res, body) ->
+ throw e if e
+ throw errorStatus 200 if res.statusCode != 200
+ assert.equal(res.headers['content-type'], mime.json)
+ assert.equal(body.resource, 'foo')
+ console.log 'GET /'
+ end()
+
+ counter++
+
+ # post to root
+ request.post url, json: {foo:'bar'}, (e, res, body) ->
+ throw e if e
+ throw errorStatus 201 if res.statusCode != 201
+ assert.equal(res.headers['content-type'], mime.json)
+ assert.equal(body.resource, 'foo')
+ assert.equal(body.params.foo, 'bar')
+ console.log 'POST / via json'
+ end()
+
+ counter++
+
+ # put to root
+ request.put url + '/1', json: {foo: 'bar2'}, (e, res, body) ->
+ throw e if e
+ throw errorStatus 200 if res.statusCode != 200
+ assert.equal(res.headers['content-type'], mime.json)
+ assert.equal(body.resource, 'foo')
+ assert.equal(body.params.foo, 'bar2')
+ assert.equal(body.id, 1)
+ console.log 'PUT / via json'
+ end()
+ #
+ counter++
+
+ # put to root
+ request.del url + '/1', json: true, (e, res, body) ->
+ throw e if e
+ throw errorStatus 200 if res.statusCode != 200
+ assert.equal(res.headers['content-type'], mime.json)
+ assert.equal(body.resource, 'foo')
+ assert.equal(body.id, 1)
+ console.log 'DELETE / via json'
+ end()
+
View
@@ -0,0 +1,69 @@
+request = require 'request'
+assert = require 'assert'
+apprentice = require '../'
+mime = require '../lib/mime'
+pin = require 'linchpin'
+
+pin.on 'GET', (req, res) -> res.text 'hello world'
+pin.on 'POST', (req, res) -> res.text 'foo=' + req.params.foo, 201
+pin.on 'PUT', (req, res) -> res.text 'foo=' + req.params.foo
+pin.on 'DELETE', (req, res) -> res.text 'delete me'
+
+#pin.on 'LOG', (entry) -> console.log entry
+
+counter = 0
+
+# apprentice.httpServer.on 'request', (req, res) ->
+# req.connection.setTimeout = 20000
+
+apprentice.httpServer.listen 3000, ->
+ url = 'http://localhost:3000'
+ errorStatus = (code) -> new Error("Status Code is not #{code}")
+ end = ->
+ counter--
+ if counter is 0 then apprentice.httpServer.close()
+
+ counter++
+
+ # route to root
+ request url, (e, res, body) ->
+ throw e if e
+ throw errorStatus 200 if res.statusCode != 200
+ assert.equal(res.headers['content-type'], mime.text)
+ assert.equal(body, 'hello world')
+ console.log 'GET /'
+ end()
+
+ counter++
+
+ # post to root
+ request.post url, body: 'foo=bar', headers: { 'accept': mime.text, 'content-type': mime.form}, (e, res, body) ->
+ throw e if e
+ throw errorStatus 201 if res.statusCode != 201
+ assert.equal(res.headers['content-type'], mime.text)
+ assert.equal(body, 'foo=bar')
+ console.log 'POST / via form-urlencoded'
+ end()
+
+ counter++
+
+ # put to root
+ request.put url, body: 'foo=bar2', headers: { 'accept': mime.text, 'content-type': mime.form}, (e, res, body) ->
+ throw e if e
+ throw errorStatus 200 if res.statusCode != 200
+ assert.equal(res.headers['content-type'], 'text/plain')
+ assert.equal(body, 'foo=bar2')
+ console.log 'PUT / via form-urlencoded'
+ end()
+
+ counter++
+
+ # put to root
+ request.del url, (e, res, body) ->
+ throw e if e
+ throw errorStatus 200 if res.statusCode != 200
+ assert.equal(res.headers['content-type'], 'text/plain')
+ assert.equal(body, 'delete me')
+ console.log 'DELETE /'
+ end()
+

0 comments on commit 937e17a

Please sign in to comment.