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

in #steemdev7 years ago (edited)

(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)

Sort:  

Anyone know why "reblogged_by": [] array is always empty?

Haha, I just had to laugh at the coincidence of landing here and this is the first comment I see.

Here are some ways to get them if anyone was trying to find the reblogged_by entries:

https://steemit.com/steemjs/@money-dreamer/10-sbd-steemjs-programming-question

Some interesting things I noted in the arrays:

  • 'Nix Dawn-of-Time last_payout timestamp, assume due to null value?:

"last_payout": "1970-01-01T00:00:00",

  • 'Nix DoT-minus-1 max_cashout_time timestamp:

"max_cashout_time": "1969-12-31T23:59:59",

  • Weighting & payout of 5 decimal places 10000:

"reward_weight": 10000, "percent_steem_dollars": 10000,

  • Max payout would be nice :D

"max_accepted_payout": "1000000.000 SBD",

  • Comment body is truncated @ carriage return (as abstract until loaded)?:

"body": "I wish I had the time to experiment...",

depth and children is interesting, I would've expected depth to be determined by parent/child ancestry & the required rendering intention applied accordingly. Wonder if it's used/intended for anything further? Just seems like it could be used to override an objects natural position, like 'pull-left' to depth=0...

Thanks once again for sharing the field notes of your sojourns in SteemitAPI, I really enjoy them.

Yes - I assume that the Unix epoch dates are simply due to null values in this case.

And the 10000 numbers represent two decimal places (i.e., 100.00).

That comment body was truncated by me in the interest of brevity (and I added the "...").

depth is determined by parent/child ancestry. The first level comments of a post are depth 1 (i.e., consider the post to be depth 0). The replies of those comments are depth 2, and their replies are depth 3, etc.

When rendering, I probably would use nested <ul> so that I wouldn't necessarily have to worry about the depth, though. I only mention it in case each node was rendered individually and you had to figure out the indent level.

Thanks for reading!

Thanks for clarifying, & congrats on the @steemitboard steemitboard total payout received award total payout received award!

Upvoted and following!

Hope i can learn more from you

Coding for you looks like its your native language! for me, coding was never a strong point but i try to improve on it.

(Can you please look at my latest post and maybe participate a bit, your help is very much needed and very much appreciated. In that project (SteePi, (iot)) i want to check for new upvotes/transfers and turn on and off a LED when there are new ones)

Upvoted and also resteemed!

Does this mean that all the protocols and functions are written in javascript and if so, what avenues do you suggest for one to learn to code at that level?

steem.js is a JavaScript wrapper around the API. It's more of a simple passthrough, though, so when you call one of the JavaScript functions, it passes along the function name and arguments to the Steem node that you are connected to, and that's where the function executes (which then sends the results back to JavaScript).

Congratulations @jfollas! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

Award for the total payout received

Click on any badge to view your own Board of Honor on SteemitBoard.
For more information about SteemitBoard, click here

If you no longer want to receive notifications, reply to this comment with the word STOP

By upvoting this notification, you can help all Steemit users. Learn how here!

MSSING CLOSE ")" HERE: console.log(JSON.stringify(replies, null, 2);