Permalink
Browse files

Merge remote-tracking branch 'mashery/master'

Conflicts:
	app.js
	package.json
  • Loading branch information...
2 parents e7c7cbd + d8f5732 commit 28189a646b2b512f383d3c4bcb079ae52e5aefe5 @jonnolen jonnolen committed Apr 26, 2012
Showing with 98 additions and 20 deletions.
  1. +81 −6 README.md
  2. +14 −11 app.js
  3. +3 −3 package.json
View
@@ -12,7 +12,6 @@ I/O Docs is a live interactive documentation system for RESTful web APIs. By def
levels in a JSON schema, I/O Docs will generate a JavaScript client interface. API calls can be executed from this interface, which are then proxied through the I/O Docs server with payload data cleanly formatted (pretty-printed if JSON or XML).
You can find the latest version here: [https://github.com/mashery/iodocs](https://github.com/mashery/iodocs)
-You can find a demo of it running here: [http://iodocs.demo.mashery.com](http://iodocs.demo.mashery.com)
However, we recommend that you install I/O Docs with *npm*, the Node package manager. See instructions below.
@@ -46,9 +45,10 @@ These will be automatically installed when you use any of the above *npm* instal
2. [oauth](https://github.com/ciaranj/node-oauth) - oauth library
3. [redis](https://github.com/mranney/node_redis) - connector to Redis
3. [connect-redis](https://github.com/visionmedia/connect-redis) - Redis session store
-4. [hashlib](https://github.com/brainfucker/hashlib) - used for signatures
-5. [querystring](https://github.com/visionmedia/node-querystring) - used to parse query string
-6. [jade](http://jade-lang.com/) - the view engine
+4. [querystring](https://github.com/visionmedia/node-querystring) - used to parse query string
+5. [jade](http://jade-lang.com/) - the view engine
+
+Note: hashlib is no longer a required module -- we're using the internal crypto module for signatures and digests.
RUNNING I/O DOCS
----------------
@@ -145,7 +145,7 @@ Line:
Ex: "/v1"
- In the Example #2 below, there is also "privatePath"
+ In the Example #3 below, there is also "privatePath"
which is used for endpoints behind protected resources.
6. "auth" key value is the auth method. Valid values can be:
@@ -163,7 +163,82 @@ Line:
---
-### Example #2 - Twitter API config that uses 3-legged OAuth
+### Example #2 - Explanation of each field in an example API config that uses basic key authentication with signatures (signed call).
+
+```js
+"upper": {
+ "name": "Upper API",
+ "protocol": "http",
+ "baseURL": "api.upper.sample.com",
+ "publicPath": "/v3",
+ "auth": "key",
+ "keyParam": "api_key_var_name",
+ "signature": {
+ "type": "signed_md5",
+ "sigParam": "sig",
+ "digest": "hex"
+ }
+}
+```
+
+Line:
+
+1. Handle of the API. It is used to pull up the client
+ interface in the URL:
+
+ Ex: http://127.0.0.1:3000/upper
+
+2. "name" key value is a string that holds the name
+ of the API that is used in the Jade template output.
+
+3. "protocol" key value is either *http* or *https*
+
+4. "baseURL" key value is the host name of
+ the API calls (should not include protocol)
+
+5. "publicPath" key value is the full path prefix prepended
+ to all method URIs. This value often includes the version
+ in RESTful APIs.
+
+ Ex: "/v3"
+
+ In the Example #3 below, there is also "privatePath"
+ which is used for endpoints behind protected resources.
+
+6. "auth" key value is the auth method. Valid values can be:
+
+ "key" - simple API key in the URI
+ "oauth1" - OAuth 1.0/1.0a
+ "" - no authentication
+
+7. "keyParam" key value is the name of the query parameter that
+ is added to an API request when the "auth" key value from
+ (5) is set to "key"
+
+8. "signature" is a JSON object that contains the details about
+ the API call signing requirements. The signature routine coded
+ in app.js is a hash of the string concatenation of API key,
+ API key secret and timestamp (epoch).
+
+9. "type" key value is either *signed_md5* or *signed_sha256*.
+ More signature methods are available with crypto.js, but have
+ not been included in the code as options.
+
+10. "sigParam" key value is the name of the query parameter that
+ is added to an API request that holds the digital signature.
+
+11. "digest" key value is the digest algorithm that is used.
+ Values can be *hex*, *base64* or *binary*.
+
+12. Closing curly-bracket for the "signature" object
+
+13. Closing curly bracket for main object.
+
+
+---
+
+
+### Example #3 - Twitter API config that uses 3-legged OAuth
```js
"twitter": {
View
25 app.js
@@ -27,22 +27,21 @@
var express = require('express'),
util = require('util'),
fs = require('fs'),
- sys = require('sys'),
OAuth = require('oauth').OAuth,
query = require('querystring'),
url = require('url'),
http = require('http'),
https = require('https'),
+ crypto = require('crypto'),
redis = require('redis'),
- RedisStore = require('connect-redis')(express),
- crypto = require('crypto');
+ RedisStore = require('connect-redis')(express);
// Configuration
try {
var configJSON = fs.readFileSync(__dirname + "/config.json");
var config = JSON.parse(configJSON.toString());
} catch(e) {
- sys.puts("File config.json not found or is invalid. Try: `cp config.json.sample config.json`");
+ console.error("File config.json not found or is invalid. Try: `cp config.json.sample config.json`");
process.exit(1);
}
@@ -312,7 +311,7 @@ function processRequest(req, res, next) {
privateReqURL = apiConfig.protocol + '://' + apiConfig.baseURL + apiConfig.privatePath + methodURL + ((paramString.length > 0) ? '?' + paramString : ""),
options = {
headers: {},
- protocol: apiConfig.protocol,
+ protocol: apiConfig.protocol + ':',
host: baseHostUrl,
port: baseHostPort,
method: httpMethod,
@@ -471,23 +470,27 @@ function processRequest(req, res, next) {
// Add API Key to params, if any.
if (apiKey != '' && apiKey != 'undefined' && apiKey != undefined) {
- options.path += '&' + apiConfig.keyParam + '=' + apiKey;
+ if (options.path.indexOf('?') !== -1) {
+ options.path += '&';
+ }
+ else {
+ options.path += '?';
+ }
+ options.path += apiConfig.keyParam + '=' + apiKey;
}
// Perform signature routine, if any.
if (apiConfig.signature) {
if (apiConfig.signature.type == 'signed_md5') {
// Add signature parameter
var timeStamp = Math.round(new Date().getTime()/1000);
- var hash = crypto.createHash('md5');
- var sig = hash.update('' + apiKey + apiSecret + timeStamp + '').digest('base64');
+ var sig = crypto.createHash('md5').update('' + apiKey + apiSecret + timeStamp + '').digest(apiConfig.signature.digest);
options.path += '&' + apiConfig.signature.sigParam + '=' + sig;
}
else if (apiConfig.signature.type == 'signed_sha256') { // sha256(key+secret+epoch)
// Add signature parameter
var timeStamp = Math.round(new Date().getTime()/1000);
- var hash = crypto.createHash('sha256');
- var sig = hash.update('' + apiKey + apiSecret + timeStamp + '').digest('base64');
+ var sig = crypto.createHash('sha256').update('' + apiKey + apiSecret + timeStamp + '').digest(apiConfig.signature.digest);
options.path += '&' + apiConfig.signature.sigParam + '=' + sig;
}
}
@@ -672,4 +675,4 @@ if (!module.parent) {
var port = process.env.PORT || config.port;
app.listen(port);
console.log("Express server listening on port %d", app.address().port);
-}
+}
View
@@ -25,12 +25,12 @@
"express": "2.5.8",
"jade": "0.13",
"oauth": "0.9.3",
- "querystring": "0.1.0",
- "redis": "0.6.6"
+ "redis": "0.6.6",
+ "querystring": "0.1.0"
},
"devDependencies": {},
"main": "index",
"engines": {
"node": ">= 0.4.0"
}
-}
+}

0 comments on commit 28189a6

Please sign in to comment.