Skip to content

Commit

Permalink
v1.0: basic functionality, docs, tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bobholt committed Feb 27, 2015
1 parent e4fa2c8 commit 3a278bd
Show file tree
Hide file tree
Showing 20 changed files with 569 additions and 1 deletion.
62 changes: 62 additions & 0 deletions .jscsrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"disallowMixedSpacesAndTabs": true,
"disallowMultipleVarDecl": "exceptUndefined",
"disallowNewlineBeforeBlockStatements": true,
"disallowSpaceAfterObjectKeys": true,
"disallowSpaceBeforeBinaryOperators": [
","
],
"disallowSpacesInsideArrayBrackets": true,
"disallowSpacesInsideParentheses": true,
"disallowTrailingWhitespace": true,
"requireCommaBeforeLineBreak": true,
"requireLineFeedAtFileEnd": true,
"requireSpaceAfterBinaryOperators": [
"=",
",",
"+",
"-",
"/",
"*",
"==",
"===",
"!=",
"!==",
":",
"&&",
"||"
],
"requireSpaceAfterKeywords": [
"if",
"else",
"for",
"while",
"do",
"switch",
"return",
"try",
"catch"
],
"requireSpaceBeforeBinaryOperators": [
"=",
"+",
"-",
"/",
"*",
"==",
"===",
"!=",
"!==",
"&&",
"||"
],
"requireSpaceBeforeBlockStatements": true,
"requireSpacesInFunctionExpression": {
"beforeOpeningCurlyBrace": true
},
"safeContextKeyword": ["self"],
"validateQuoteMarks": {
"escape": true,
"mark": "'"
}
}
6 changes: 6 additions & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"undef": true,
"node": true,
"esnext": true,
"expr": true
}
7 changes: 7 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
language: node_js
node_js:
- "0.10"
- "0.12"
- "iojs"
matrix:
fast_finish: true
4 changes: 4 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
v1.0.0:
date: 2015-02-27
changes:
- Initial release.
102 changes: 101 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,102 @@
# kapow
# Kapow!

An http error library


[![Build Status](https://secure.travis-ci.org/bobholt/kapow.png)](http://travis-ci.org/bobholt/kapow)

Kapow! consolidates boilerplate HTTP information into a single easy-to-use
library. You tell Kapow! that you want an error with a particular httpStatus
code, and it fills in the basics for you. It defines and returns a
`RequestError` object based on JavaScript's native `Error` object.

## Installation

`npm install kapow`

## Usage

### Basics:

To get an JavaScript Error object suitable for throwing or passing along, give
Kapow! a status code, a message, and arbitrary data you want to include:

```js
const Kapow = require('kapow');

var code = 404;
var message = 'Ain\'t nobody here here but us chickens.';
var data = {a: 1};
var err = Kapow(code, message, data);

err;
// Returns:
// { [RequestError: Ain't nobody here but us chickens.]
// httpStatus: '404',
// title: 'Not Found',
// message: 'Ain\'t nobody here but us chickens.',
// name: 'RequestError',
// data: { a: 1 } }
```

All arguments to Kapow! are optional. Kapow! will try to figure out sensible
defaults based on the information you did pass in.

This error can be either thrown immediately or passed on through your
application to eventually send the user an informative HTTP response.

### Wrapping an Existing Error:

If your app hands you an error, and you just want to decorate it, you can
use the static `wrap` method on Kapow!:

```js
const Kapow = require('kapow');

somePromise.then().catch(function(err) {
Kapow.wrap(err, 404, 'Ain\'t nobody here at all.');
});
```

### Changing Your Error:

Once you get the RequestError object back, you can augment it however you like:

```js
const Kapow = require('kapow');

var err = Kapow(403, 'Don\'t you come back no more');

err.title = 'Hit the Road Jack';

err;

// Returns:
// { [RequestError: Don't you come back no more]
// httpStatus: '403',
// title: 'Hit the Road Jack',
// message: 'Don\'t you come back no more',
// name: 'RequestError',
// data: undefined }
```

### Don't Like Numbers?

You can call Kapow with the camelized version of the IETF's official error.
See [Kapow!'s complete error code list](https://github.com/bobholt/kapow/blob/master/lib/error_codes.js) for all supported codes:

```js
const Kapow = require('kapow');

var err = Kapow('forbidden', 'Fie! Forsooth Begone!');

err;

// Returns:
// { [RequestError: Fie! Forsooth Begone]
// httpStatus: '403',
// title: 'Forbidden',
// message: 'Fie! Forsooth Begone',
// name: 'RequestError',
// data: undefined }
```
24 changes: 24 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const errorCodes = require('./lib/error_codes');
const partial = require('./lib/partial');
const camelize = require('./lib/camelize');
const RequestError = require('./lib/request_error');
const wrap = require('./lib/wrap');

function Kapow(code, message, data) {
if (!(this instanceof Kapow)) {
return new Kapow(code, message, data);
}
code = code || 400;
return this[code](message, data);
}

// Attach Error handlers for each status code and status title
Object.keys(errorCodes).forEach(function(key) {
Kapow.prototype[key] =
Kapow.prototype[camelize(errorCodes[key])] = partial(RequestError, key);
});

// Static methods
Kapow.wrap = wrap;

module.exports = Kapow;
15 changes: 15 additions & 0 deletions lib/camelize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
Modified version of Ember.js camelize
https://github.com/emberjs/ember.js/blob/v1.10.0/packages/ember-runtime/lib/system/string.js#L19-L25
Ember.js Copyright (c) 2015 Yehuda Katz, Tom Dale and Ember.js contributors
(MIT License)
*/

module.exports = function(str) {
return str.replace(/('|")/g, '')
.replace(/(\-|_|\.|\s)+(.)?/g, function(match, separator, chr) {
return chr ? chr.toUpperCase() : '';
}).replace(/^([A-Z])/, function(match) {
return match.toLowerCase();
});
};
62 changes: 62 additions & 0 deletions lib/error_codes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
module.exports = {
// RFC 7231 - http://tools.ietf.org/html/rfc7231#page-47
'400': 'Bad Request',
'401': 'Unauthorized',
'402': 'Payment Required',
'403': 'Forbidden',
'404': 'Not Found',
'405': 'Method Not Allowed',
'406': 'Not Acceptable',
'407': 'Proxy Authentication Required',
'408': 'Request Timeout',
'409': 'Conflict',
'410': 'Gone',
'411': 'Length Required',
'412': 'Precondition Failed',
'413': 'Request Entity Too Large',
'414': 'Request-URI Too Long',
'415': 'Unsupported Media Type',
'416': 'Requested Range Not Satisfiable',
'417': 'Expectation Failed',
'426': 'Upgrade Required',

// RFC 2324 :-P - http://tools.ietf.org/html/rfc2324
'418': 'I\'m A Teapot',

// RFC 4918 - https://tools.ietf.org/html/rfc4918#page-78
'422': 'Unprocessable Entity',
'423': 'Locked',
'424': 'Failed Dependency',

// RFC 6585 - http://tools.ietf.org/html/rfc6585
'428': 'Precondition Required',
'429': 'Too Many Requests',
'431': 'Header Fields Too Large',

// Internet-Draft -
// http://tools.ietf.org/html/draft-tbray-http-legally-restricted-status-05
'451': 'Unavailable For Legal Reasons',

// RFC 7231 - http://tools.ietf.org/html/rfc7231#page-47
'500': 'Internal Server Error',
'501': 'Not Implemented',
'502': 'Bad Gateway',
'503': 'Service Unavailable',
'504': 'Gateway Timeout',
'505': 'HTTP Version Not Supported',

// RFC 2295 - https://tools.ietf.org/html/rfc2295#page-25
'506': 'Variant Also Negotiates',

// RFC 4918 - https://tools.ietf.org/html/rfc4918#page-78
'507': 'Insufficient Storage',

// RFC 5842 - https://tools.ietf.org/html/rfc5842#page-31
'508': 'Loop Detected',

// RFC 2774 - https://tools.ietf.org/html/rfc2774#page-11
'510': 'Not Extended',

// RFC 6585 - http://tools.ietf.org/html/rfc6585
'511': 'Network Authentication Required'
};
19 changes: 19 additions & 0 deletions lib/partial.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
partial function Copyright © 2010 “Cowboy” Ben Alman
dual licensed under the MIT and GPL licenses
http://benalman.com/news/2012/09/partial-application-in-javascript/
*/

module.exports = function partial(fn /*, args...*/) {
// A reference to the Array#slice method.
var slice = Array.prototype.slice;

// Convert arguments object to an array, removing the first argument.
var args = slice.call(arguments, 1);

return function() {
// Invoke the originally-specified function, passing in all originally-
// specified arguments, followed by any just-specified arguments.
return fn.apply(this, args.concat(slice.call(arguments, 0)));
};
};
16 changes: 16 additions & 0 deletions lib/request_error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const errorCodes = require('./error_codes');

function RequestError(code, message, data) {
if (!(this instanceof RequestError)) {
return new RequestError(code, message, data);
}
this.httpStatus = code || 400;
this.title = errorCodes[this.httpStatus];
this.message = message || 'Client Error';
this.name = 'RequestError';
this.data = data;
}

RequestError.prototype = new Error();

module.exports = RequestError;
10 changes: 10 additions & 0 deletions lib/wrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const errorCodes = require('./error_codes');
const RequestError = require('./request_error');

module.exports = function(error, code, message) {
error = error || new RequestError();
error.httpStatus = code || 400;
error.message = message || error.message;
error.title = errorCodes[error.httpStatus];
return error;
};
43 changes: 43 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"name": "kapow",
"version": "1.0.0",
"description": "An http error library",
"main": "index.js",
"scripts": {
"test": "npm run lint && npm run style && istanbul cover _mocha -- -b -R spec",
"style": "jscs lib test",
"lint": "jshint index.js lib test"
},
"repository": {
"type": "git",
"url": "https://github.com/bobholt/kapow.git"
},
"keywords": [
"http",
"error",
"status",
"codes"
],
"author": {
"name": "Bob Holt",
"url": "http://bobholt.me"
},
"licenses": [
{
"type": "MIT",
"url": "https://github.com/bobholt/kapow/blob/master/LICENSE"
}
],
"bugs": {
"url": "https://github.com/bobholt/kapow/issues"
},
"homepage": "https://github.com/bobholt/kapow",
"devDependencies": {
"chai": "^2.1.0",
"istanbul": "^0.3.6",
"jscs": "^1.11.3",
"jshint": "^2.6.0",
"lodash": "^3.3.1",
"mocha": "^2.1.0"
}
}
11 changes: 11 additions & 0 deletions test/.jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "../.jshintrc",
"globals": {
"before": true,
"beforeEach": true,
"after": true,
"describe": true,
"it": true,
"expect": true
}
}
3 changes: 3 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
describe('KapowAll', function() {
require('./unit');
});
Loading

0 comments on commit 3a278bd

Please sign in to comment.