Skip to content


Documenting your API with IODocs on Heroku

Neil Mansilla over at Mashery has created an awesome new system called IODocs, which can be used to create a system for browsing through OAuth-secured APIs. Being a Developer Advocate at LinkedIn, I decided to try and get this up and running with LinkedIn’s API.  Since it was LinkedIn’s internal hackday on Friday, I decided to go the extra mile and try to build the configuration dynamically from our nascent discovery API system, and run it on one of Heroku’s node.js hosted systems.

Thanks in part to a heavy piece of furniture (which fell on me on Friday, relegating me to bed rest for the weekend) I got it working. You can visit the LinkedIn API Documentation site and use your LinkedIn API key and secret to browse through the many API resources LinkedIn has to offer.

Getting the IODocs system running on Heroku required several steps, but once you have them it’s pretty straightforward. So I share them with you here so you can get IODocs running on your own Heroku instance, in the hopes that all of the OAuth APIs out there can leverage this functionality and improve developers’ lives.

Consider this an inclusive set of instructions to the ones they have on the site.

  1. Get “Local Workstation Setup” done from http://devcenter.heroku.com/articles/node-js
  2. Do the initial IODocs setup
    % git clone http://github.com/mashery/iodocs.git
    % cd iodocs/
    % npm install
    % echo "web: node app.js" > Procfile
    % cp config.json.sample config.json
    % vi config.json (remove address line)
  3. Add the following block under “var db;” to app.js:
    if (process.env.REDISTOGO_URL) {
       var rtg   = require("url").parse(process.env.REDISTOGO_URL);
       db = require("redis").createClient(rtg.port, rtg.hostname);
       db.auth(rtg.auth.split(":")[1]);
    } else {
       db = redis.createClient(config.redis.port, config.redis.host);
       db.auth(config.redis.password);
    }
    
    And then this in the Load API Configs section, after reading the config file:
    
    var app = module.exports = express.createServer();
    
    var hostname, port, password
    
    if (process.env.REDISTOGO_URL) {
        var rtg   = require("url").parse(process.env.REDISTOGO_URL);
        hostname = rtg.hostname;
        port = rtg.port;
        password = rtg.auth.split(":")[1];
    } else {
        hostname = config.redis.host;
        port = config.redis.port;
        password = config.redis.password;
    }
    
    
    
  4. Add a LinkedIn block to public/data/apiconfig.json:
    "linkedin": {
       "name": "LinkedIn",
       "protocol": "http",
       "baseURL": "api.linkedin.com",
       "publicPath": "",
       "privatePath": "/v1",
       "auth": "oauth",
       "oauth": {
          "type": "three-legged",
          "requestURL": "https://api.linkedin.com/uas/oauth/requestToken",
          "signinURL": "https://api.linkedin.com/uas/oauth/authorize?oauth_token=",
          "accessURL": "https://api.linkedin.com/uas/oauth/accessToken",
          "version": "1.0",
          "crypt": "HMAC-SHA1"
       },
       "keyParam":""
     },
  5. Copy linkedin.json into your public/data folder
  6. Set up your git repository for heroku
    % git init
    % git add .
    % git add -f config.json Procfile public/data/*
    % git commit -m "init"
  7. Set up heroku
    % heroku create --stack cedar;
    % heroku addons:add redistogo [note: this may require that you add a credit card to your heroku account.  there is no charge, though]
    % heroku addons:add logging 
    % git push heroku master
    % heroku ps:scale web=1
    
    

Once you’ve gotten all this set up, you’re ready to rock.  Heroku will give you the right system name and port, and you can use ‘heroku logs’ to check the logs for the node.js server.

You can set up your own APIs using the config file – the IODocs documentation is fantastic, with OCD-level detail on how to set up configurations for new APIs, and I’m certain you can make it work with whatever you’re trying to use.

 

Posted in API, LinkedIn.

Tagged with , , , , .

  • http://jason.pureconcepts.net Jason McCreary

    Thank you for your post. I had been wanting to try IODocs for some time now. However, I was not familiar with node.js or Heroku. This got me started.

    Unfortunately the app crashed at first on Heroku. I made a few modifications.

    The app port needed to be modified:

    // CORE UPDATE: switch to production port
    var port = process.env.PORT || config.port;
    app.listen(port, config.address);

    The redis port is used for more than the lines you noted. Instead the following code overwrites the core `config` object making it more flexible.

    // CORE UPDATE:
    if (process.env.REDISTOGO_URL) {
    // use production (Heroku) redis configuration
    // overwrite `config` to keep it simple
    var rtg = require(‘url’).parse(process.env.REDISTOGO_URL);
    config.redis.port = rtg.port;
    config.redis.host = rtg.hostname;
    config.redis.password = rtg.auth.split(“:”)[1];
    }

    I also didn’t need to remove the address line from config.json.

    Hope this helps a future reader save some time.

  • Pingback: Installing, Configuring, and Deploying I/O Docs

  • Mike Papper

    Have you tried running with several dynos? I dont have node.js experience so Im wondering if the proxy-ing effort done by node,js will work in the multi-dyno Heroku situation.

    Also, has anyone figured out a way to store and retrieve the JSON data not from a flat file but from some data store? This would allow us to update the API without needing to deploy the app.

    Mike

  • Arun Avudainayagam

    I am getting an App crash error in Heroku. I am very new to node.js

    These are my changes in app.js,


    // Redis connection
    //
    var defaultDB = '0';
    var port = process.env.PORT || config.port;
    app.listen(port, config.address);
    if(config.redis) {
    config.redis.database = config.redis.database || defaultDB;
    if (process.env.REDISTOGO_URL || process.env.REDIS_URL) {
    var rtg = require("url").parse(process.env.REDISTOGO_URL || process.env.REDIS_URL);
    config.redis.host = rtg.hostname;
    config.redis.port = rtg.port;
    config.redis.password = rtg.auth && rtg.auth.split(":")[1] ? rtg.auth.split(":")[1] : '';
    }
    var db = redis.createClient(config.redis.port, config.redis.host);
    if (process.env.REDISTOGO_URL) {
    var rtg = require("url").parse(process.env.REDISTOGO_URL);
    db = require("redis").createClient(rtg.port, rtg.hostname);
    db.auth(rtg.auth.split(":")[1]);
    } else {
    db = redis.createClient(config.redis.port, config.redis.host);
    db.auth(config.redis.password);
    }

    And in the “Load API Configs” section,


    // Load API Configs
    //
    config.apiConfigDir = path.resolve(config.apiConfigDir || 'public/data');
    if (!fs.existsSync(config.apiConfigDir)) {
    console.error("Could not find API config directory: " + config.apiConfigDir);
    process.exit(1);
    }

    var app = module.exports = express();
    var hostname, port, password
    if (process.env.REDISTOGO_URL) {
    var rtg = require("url").parse(process.env.REDISTOGO_URL);
    hostname = rtg.hostname;
    port = rtg.port;
    password = rtg.auth.split(":")[1];
    } else {
    hostname = config.redis.host;
    port = config.redis.port;
    password = config.redis.password;
    }

    Can you please help me find why the App keeps crashing.

    Thanks,
    Arun