Write a Steemit Web App: Part 10 - Retrieving Comments with getContentReplies()

(Previous Post: Part 9)

In the previous two posts, I demonstrated a few different ways to retrieve content (i.e., blog posts). Blog posts also have comments associated with them, which is where the interactions between authors and readers take place. So, let's look at what it takes to fetch the comments for a post.

Introducing getContentReplies()

Consider the following code:

steem.api.getContentAsync(author, permlink)
  .then(function(post) {
    steem.api.getContentRepliesAsync(author, permlink)
      .then(function(replies) {
        console.log(JSON.stringify(replies, null, 2);
      });
  });


Here, there are two "get content" functions called with the same arguments: author and permlink. The first function (getContent) fetches the blog post itself that the author/permlink point to. After that content comes back, the replies (comments) for that blog post are fetched using getContentReplies.

Sample replies array:

[
  {
    "id": 8529064,
    "author": "neuromancer",
    "permlink": "re-jfollas-write-a-steemit-web-app-part-9-retrieving-content-with-getdiscussionsby-20170728t074055777z",
    "category": "steemdev",
    "parent_author": "jfollas",
    "parent_permlink": "write-a-steemit-web-app-part-9-retrieving-content-with-getdiscussionsby",
    "title": "",
    "body": "I wish I had the time to experiment...",
    "json_metadata": "{\"tags\":[\"steemdev\"],\"app\":\"steemit/0.1\"}",
    "last_update": "2017-07-28T07:41:06",
    "created": "2017-07-28T07:41:06",
    "active": "2017-07-31T07:19:48",
    "last_payout": "1970-01-01T00:00:00",
    "depth": 1,
    "children": 2,
    "net_rshares": 0,
    "abs_rshares": 0,
    "vote_rshares": 0,
    "children_abs_rshares": 0,
    "cashout_time": "2017-08-04T07:41:06",
    "max_cashout_time": "1969-12-31T23:59:59",
    "total_vote_weight": 0,
    "reward_weight": 10000,
    "total_payout_value": "0.000 SBD",
    "curator_payout_value": "0.000 SBD",
    "author_rewards": 0,
    "net_votes": 0,
    "root_comment": 8514653,
    "max_accepted_payout": "1000000.000 SBD",
    "percent_steem_dollars": 10000,
    "allow_replies": true,
    "allow_votes": true,
    "allow_curation_rewards": true,
    "beneficiaries": [],
    "url": "/steemdev/@jfollas/write-a-steemit-web-app-part-9-retrieving-content-with-getdiscussionsby#@neuromancer/re-jfollas-write-a-steemit-web-app-part-9-retrieving-content-with-getdiscussionsby-20170728t074055777z",
    "root_title": "Write a Steemit Web App: Part 9 - Retrieving Content with getDiscussionsBy*()",
    "pending_payout_value": "0.000 SBD",
    "total_pending_payout_value": "0.000 STEEM",
    "active_votes": [],
    "replies": [],
    "author_reputation": "8234790010",
    "promoted": "0.000 SBD",
    "body_length": 0,
    "reblogged_by": []
  },
  { ... }
]


Replies can be nested, like a tree or a graph structure. So, each reply will have a parent and may have children.

The getContentReplies function only returns the children of the content specified by author/permlink. In this case, we will get all comments that were made to the blog post itself, but will not get any replies to those first-level comments.

To walk the tree and retrieve the replies of replies, we must make recursive calls into getContentReplies for each comment that indicates that it has children (using that comment's author/permlink).

An Example

Each comment object fetched with getContentReplies will have an empty replies array. So, why not just populate that array to hold the children of each node as we walk the tree?

  let author = 'jfollas';
  let permlink = 'write-a-steemit-web-app-part-9-retrieving-content-with-getdiscussionsby';
  let comments = [];

  // Eagerly fetch all of the descendant replies (recursively)
  let fetchReplies = function (author, permlink) {
    return steem.api.getContentReplies(author, permlink)
      .then(function (replies) {
        return Promise.map(replies, function (r) {
          if (r.children > 0) {
            return fetchReplies(r.author, r.permlink)
              .then(function (children) {
                r.replies = children;
                return r;
              })
          } else {
            return r;
          }
        });
      });
  }

  steem.api.getContentAsync(author, permlink)
    .then(function (post) {
      return fetchReplies(author, permlink)
        .then(function (comments) {
          post.replies = comments;
          return post;
        });
    })
    .then(function (post) {
      console.log(JSON.stringify(post, null, 2));
    })
    .catch(console.log);
});


Note: Bluebird.js was used in this example, and Promise is a Bluebird promise.

Results (modified in the interest of space):

{
  "id": 8514653,
  "author": "jfollas",
  "permlink": "write-a-steemit-web-app-part-9-retrieving-content-with-getdiscussionsby",
  "category": "steemdev",
  "parent_author": "",
  "parent_permlink": "steemdev",
  "title": "Write a Steemit Web App: Part 9 - Retrieving Content with getDiscussionsBy*()",
  "body": "...",
  "json_metadata": "...",
  "depth": 0,
  "children": 5,
  "active_votes": [...],
  "replies": [
    {
      "id": 8514812,
      "author": "bikash-tutor",
      "permlink": "re-jfollas-write-a-steemit-web-app-part-9-retrieving-content-with-getdiscussionsby-20170728t033311808z",
      "category": "steemdev",
      "parent_author": "jfollas",
      "parent_permlink": "write-a-steemit-web-app-part-9-retrieving-content-with-getdiscussionsby",
      "depth": 1,
      "children": 0,
      "replies": [],
    },
    {
      "id": 8529064,
      "author": "neuromancer",
      "permlink": "re-jfollas-write-a-steemit-web-app-part-9-retrieving-content-with-getdiscussionsby-20170728t074055777z",
      "category": "steemdev",
      "parent_author": "jfollas",
      "parent_permlink": "write-a-steemit-web-app-part-9-retrieving-content-with-getdiscussionsby",
      "depth": 1,
      "children": 2,
      "replies": [
        {
          "id": 8733164,
          "author": "jfollas",
          "permlink": "re-neuromancer-re-jfollas-write-a-steemit-web-app-part-9-retrieving-content-with-getdiscussionsby-20170730t145341449z",
          "category": "steemdev",
          "parent_author": "neuromancer",
          "parent_permlink": "re-jfollas-write-a-steemit-web-app-part-9-retrieving-content-with-getdiscussionsby-20170728t074055777z",
          "depth": 2,
          "children": 1,
          "replies": [
            {
              "id": 8792360,
              "author": "neuromancer",
              "permlink": "re-jfollas-re-neuromancer-re-jfollas-write-a-steemit-web-app-part-9-retrieving-content-with-getdiscussionsby-20170731t071946486z",
              "category": "steemdev",
              "parent_author": "jfollas",
              "parent_permlink": "re-neuromancer-re-jfollas-write-a-steemit-web-app-part-9-retrieving-content-with-getdiscussionsby-20170730t145341449z",
              "depth": 3,
              "children": 0,
            }
          ],
        }
      ],
    },
    {
      "id": 8533500,
      "author": "mkt",
      "permlink": "re-jfollas-write-a-steemit-web-app-part-9-retrieving-content-with-getdiscussionsby-20170728t085844274z",
      "category": "steemdev",
      "parent_author": "jfollas",
      "parent_permlink": "write-a-steemit-web-app-part-9-retrieving-content-with-getdiscussionsby",
      "depth": 1,
      "children": 0,
      "replies": [],
    }
  ],
}



Pay attention to the depth and children properties of each comment object. If you render comments like Steemit.com does, then depth can be used to indicate how far to indent the comment under its parent. I used children in the eager-fetching code above to determine whether to fetch more replies for a given node. It can also be used for user interfaces like eSteem, which does lazy-fetching (only fetches the children of a node on demand when the user clicks a button, and only render that button if the node has children).

javascriptlogo.png

(Next Post: Part 11)

H2
H3
H4
3 columns
2 columns
1 column
13 Comments