All My Friends Are Superheroes

All My Friends Are Superheroes

This post is more than 2 years old.

A few weeks back I created an incredibly practical and not silly at all application that went through your device's contact list and "fixed" those contacts that didn't have a proper picture. The "fix" was to simply give them a random cat picture. That seems totally sensible, right?

This is practical

I was thinking about this during the weekend and it occured to me that there is an even cooler way we could fix our friends - by turning them all into superheros with the Marvel API. I've built a few apps with this API in the past (I'll link to them at the end) and I knew it had an API for returning characters. I thought - why not simply select a random character from the API and assign it to each of my contacts without a picture?

The Character endpoint of the Marvel API does not allow for random selections so I hacked up my own solution. First, I did a generic GET call on the API to get the first page of results. In that test, I was able to see the total number of characters:

Interactive tester

Given that I assume, but certainly can't verify, that they have IDs from 1 to 1485, I decided to simply select a random number between them. (I ended up going a bit below 1485 just to feel a bit safer.) I figured this would be an excellent use of OpenWhisk, so I wrote up a quick, and simple, action:

var request = require('request');
var crypto = require('crypto');

const publicKey = 'my api brings all the boys to the yard';
const privateKey = 'damn right its better than yours';

This number came from searching for characters and doing no filter. The
API said there was 1485 total results. I dropped it down to 1400 to allow
for possible deletes in the future.
const total = 1400;

function getRandomInt (min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;

function main() {

    return new Promise(function(resolve, reject) {

        let url = ''
        let selected = getRandomInt(0, total);
        url += selected;

        // add hash
        let ts = new Date().getTime();
        let hash = crypto.createHash('md5').update(ts + privateKey + publicKey).digest('hex');

        url += '&hash='+encodeURIComponent(hash)+'&ts='+ts;

        request.get(url, function(error, response, body) {
            if(error) return reject(error);
            let result = JSON.parse(body).data.results[0];

            let character = {
                picture:result.thumbnail.path + '.' + result.thumbnail.extension,
            if(result.urls && result.urls.length) {
                result.urls.forEach(function(e) {
                    if(e.type === 'detail') character.url = e.url;


exports.main = main;

I deployed this to OpenWhisk as a zipped action since crypo wasn't supported out of the box. (As an aside, that's wrong, but it's a long story, so don't worry about it now.) I then used one more wsk code to create the GET API, and I was done. And literally, that's it. 55 lines of code or so and the only real complex aspect is the hash. I do remove quite a bit of the Character record just because I didn't think it was necessary. I'm returning just the name, description, picture, and possibly a URL.

You can see this in action here:

So yeah, I'm building something totally stupid and impractical here, but I freaking love how easy it was to deploy the API to Bluemix. As I said, I've got 50ish lines of code and I'm done, and as a developer, I think that royally kicks ass.

Ok, so what about the app? I'm not going to go through all the code since I shared it in the earlier post. The basics were - get all contacts, loop over each, and if they don't have a picture, "fix it", so let's focus on that code block.

Contacts.find(["name"]).then((res) => {

	res.forEach( (contact:Contact) => {

	if(! {
		console.log('FIXING ';

		proms.push(new Promise( (resolve, reject) => {

			console.log('super hero is '+JSON.stringify(res));              
			this.toDataUrl(res.picture, function(s) {

			var f = new ContactField('base64',s,true); = [];;
			contact.nickname =;

			if(!contact.urls) contact.urls = [];

			console.log('FIXED ';;




	Promise.all(proms).then( (res) => {

		console.log('all done, fixed is  '+fixed);
		let subTitle, button;

		if(fixed === 0) {
			subTitle = "Sorry, but every single one of your contacts had a picture. I did nothing.";
			button = "Sad Face";
		} else {
			subTitle = `I've updated ${fixed} contact(s). Enjoy!`;
			button = "Awesome";      

			title:'Contacts Updated',



Previously the logic to handle finding a random cat was synchronous, but now we've got an asynch call out to my service so I had to properly handle that in my loop. Everything is still wrapped in a Promise though because I'm still converting the image to base64 for storage on the phone. (And that's probably a violation of the API, but I'm not releasing this to the market, so, yeah.) Outside of that, the code is the same. I call the API in this simple provider:

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';

export class SuperHero {

  apiUrl:string = '';

  constructor(public http: Http) {

  getSuperHero() {
    return this.http.get(this.apiUrl + '?safaricanbiteme='+Math.random()).map(res => res.json());


So what's with the random code at the end? See this post about a stupid Safari caching bug that impacts it. If you want to see the rest of the Ionic code, you can find it here:

And the result?


Pure awesomeness. (Ok, maybe just to me.) If your curious about my other uses of the Marvel API, here are a few links:

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA

Archived Comments

Comment 1 by glynn_bird posted on 1/18/2017 at 4:29 PM

Great post Raymond. I'm just getting started with OpenWhisk myself.

I notice that you have the publicKey and privateKey as constants (hard-coded) at the top of your OpenWhisk action. Is this best practice?

I know that you can pass in files of parameters with --params-file when creating the action. Is that better practice? Or doesn't it matter?

Comment 2 (In reply to #1) by Raymond Camden posted on 1/18/2017 at 4:40 PM

Ok so given that I've been a OW developer for approximately 5 minutes, here are my thoughts on THIS particular use case.

* The users of my REST API are not expected to have a key.
* I could use default params and keep my keys out of the code.
* But it... "feels" wrong to use params like this. To me, if I do this, I should expect/document folks to possibly pass params if they want to use their own keys.

Since I'm not doing that, using params for what is a config value seems wrong.

Oh - so that being said - when I built this action, I did NOT know I was going to need to zip it up. I could easily move the keys into config.json, require that, and keep the code a bit more pure. That I *would* do!