Building A Hacker News Clone Without Writing Any Backend Code

6,347
Stamplay
API Lego for developers. Code less. Build more.

Editor's note: By Giuliano Iacobelli, ‎Co-founder & CEO at Stamplay



Clone Comparision


Contents

Building The Backend

Building The Frontend

Hacker News is a popular social news website focusing on computer science and entrepreneurship. If you’re a hacker or work in the startup space, you’ve almost certainly heard of it and perhaps even contribute to it!

Most front end developers often find themselves creating rich UI’s for their projects with frameworks like Angular and React but there comes a point where your app needs data, persistence, business logic, email and a whole host of other behaviours that are usually the domain of back-end developers. Stamplay is a service that aims to make these aspects of application development as easy as filling out a form.

Stamplay is a web-based development platform that gives developers an incredibly fast way to build fully integrated applications. Stamplay handles the trouble of talking to many different APIs for you so you don’t have to.

Stackshare users can try it now for free and benefit of an exclusive coupon to get 6 months free of Plus plan if they signup before Sept 30th and use the coupon code STAMPLAY_<3_STACKSHARE when you upgrade your application’s plan in the editor dashboard.

In this tutorial we’ll show you how to glue together Stamplay, Algolia, and Mailgun APIs to build a clone of Hacker News. The app will feature the following functionalities:

  • users can signup and login with email and password
  • users can submit posts
  • users can upvote and comment on posts
  • users can earn points for comments and creating posts
  • posts will be indexed in Algolia and users will have typeahead
  • search users will receive a welcome email after they signup using the Mailgun API

Building the backend:

Creating the app

In the Stamplay Editor give your new app a unique name and then click the Create button. We’ve called our app hnews2.

You’ll now land on your dashboard for this app. Take note of this page as it has some important information for connecting our front-end to Stamplay.

Creating A RESTful API For Posts

We’re going to need “posts” if we’re going to have a hacker news-like app. Let’s go over to Stamplay and set up our Post Object before wiring it into our application.

On your app’s dashboard, click the Object link in the left hand menu then click + Add. Type post in the Object Name field then hit enter to start filling out its properties.

Post Properties

Testing API endpoints with the API Console

Stamplay has an API console that helps you to interact with your application. It let’s you perform API actions to get / set data and see how your application responds.

Let’s use the console to add our first post (we’ll add posts using our own app in just a moment). Click on API Console in the left hand menu of the Stamplay editor. From the Operation menu, choose “Create object”.

In the API URL field, choose “post” from the dropdown.

API Console

A form will appear asking for the properties of the Post you want to add. We’ll see the request as it’s sent to your app’s API, and eventually we’ll get a response. All going well, it should be a 200 OK.

Allowing users to Sign up / Login

On Hacker News only registered users are able to add new posts. Stamplay has already solved most of the user management lifecycle for us making signup and login very easy. Email+Password authentication is enabled by default.

Here you can also choose from a range of authentication solutions for your Stamplay application but in this demo we’re not going to use them.

Sending Email On User Registration

Let’s send a welcome email to new users and use the Mailgun API to do this.

Click on “Components” under “Tasks” in the Stamplay left hand menu, then select Mailgun component. Copy and paste on Stamplay the Mailgun domain and API Key that we can see on our Mailgun dashboard.

After this is connected let’s click on “Manage” under “Tasks” in the Stamplay left hand menu, then click “New Task”. We’re going to select: “When a user signs up, Mailgun – Send Email”. On User Sign Up Send Email

Click “Continue” to get to Step 3 where you can use the values on the right to populate your email.

Configure Email Template

Click “Continue” once again, name the task and then let’s save it.

Indexing Posts on the Algolia Platform

As more and more posts get added to our app, it’s going to become impractical to use a simple list to choose and find interesting posts we’d like to read. So let’s use Algolia, a hosted search API (and the same one Hacker News actually uses), to implement a Typeahead search box that returns relevant results with just a few keystrokes. The service is fully integrated into Stamplay, but before moving forward you will need to create an Algolia account.

In the Stamplay Editor, we need to connect to Algolia. Go to the components, page and click Algolia. Enter your details (available on the credentials tab of your Algolia dashboard) and then click connect. We’ll need to create an index in Algolia. Algolia’s online app makes it easy to add an index and their tutorials are clear.

Add An Index On Algolia

We’ll call our index “posts” – make sure that there’s no data (dummy data) in the index to begin with.

Now we can add a new task in Stamplay. From the criteria select: When a new Object is created, push data to Algolia.

Index Post On Algolia When A Post Is Created

On the next pages we’re going to select Post (the objects we want to search) and we’ll put them into our index named books.

We’ll index the title property as title, description property as description, the url property as url and the _id property as postId:

Set Which Object Instance To Trigger Algolia Indexing Of Post

Configure Trigger Properties to be set.

Note: any posts you’ve added before this point will not be indexed. Since we’re pairing the postId on Stamplay with the one stored by Algolia you might add another task to index them when they’re updated, or since it’s test data you can delete the older posts and add new ones. New posts you add will appear in your Algolia index.

Let’s say that we want to update Algolia records with the updated number of votes that posts have received. Let’s add a new task in Stamplay. From the criteria select: When a new Object is upvoted, update data to Algolia.

The first two steps are the same as the task we created before, the third one requires us to specify separately the objectId on the Algolia platform end.

On Post Up Vote Update Algolia Record

Adding Karma Points:

User activity on Hacker News is rewarded with Karma points. We’ll implement this feature with a couple Tasks and CodeBlocks. We’ll award points to our users when they post a new content, or comment.

Create a Task, and set as "When an object is created, CodeBlock - Run Code".

On step two select the post instance to trigger on.

Configure Trigger On New Object Run Code Block

Set the Code As new_post, you will select Type In A Custom Value from the dropdown to do this.

Configure the data field, to pass the _id of our user who triggered this action to our Code Block.

Finally proceed and name the Task.

Before creating the Code Block for this Task setup another Task that triggers whenever a user comments on an post object.

Configure Code Block to Run, and Data To Pass

Setup the new task as: "When an object is commented, CodeBlock - Run Code".

On step two select the post instance to trigger on.

Configure Trigger On New Comment Run Code Block

Set the Code As new_comment, you will select Type In A Custom Value from the dropdown to do this.

Configure the data field, to pass the _id of our user who triggered this action to our Code Block.

Finally proceed and name the Task.

[Configure Code Block to Run, and Data To Pass]

Now we can create our Code Blocks from this set of tasks that will give our user points for performing these actions.

Head over to Code Blocks and create a new one. Name the first new_post just like we entered in the field in the task regarding new posts.

Inside this Code Block we will check if the user has a score already, and if they do we will add 100 points to it, otherwise set it to 100.

Configure Code Block to Add Points To User Score

Our Code Block uses the Node.js SDK, which requires you add your APP ID and API KEY to the placeholders within the Code Block.

You can grab the code for copy here for easier configuration.

Save the Code Block after editing.

Our second Code Block will be exactly the same apart from being named new_comment and the point value increase for commenting is 25 points instead of 100. But you can set the point values for the actions your prefer.

Now that the backend has been set up let’s move to the frontend!

Building the frontend:

The Stamplay CLI

In order to work with Stamplay we’ll need to connect our front-end app to Stamplay’s API. Stamplay has provided an npm package for this purpose. Go ahead and install the stamplay-cli package.

npm install -g stamplay-cli

App Configuration and Setup

Once the Stamplay CLI is installed, you can run stamplay init in your project directory to generate a stamplay.json file.

You’ll need your app’s APP ID and API KEY both of which can be found on your app dashboard as mentioned above.

After we initialize our client side app with the stamplay init command in our project directory, we will create our index.html.

Before we start coding, let’s install the required dependencies we will be using in our Hacker News clone:

Run the following bower command in your terminal: bower install jquery jquery-Mustache mustache.js algoliasearch stamplay-js-sdk --save

After you have included the SDK, the other dependencies at the bottom on the your index.html, let’s get right to making the user login and registration components.

User Registration & Sessions

By default, email and password registration on the Stamplay platform is enabled. All we need to do is create an interface to submit the correct format of data, and properties into a method on the Stamplay User Model Object.

Sessions are also enabled by default. Sessions are automatically created when users log in or they sign up for an account. By default user sessions last 7 days.

When the session is created a token is generated and stored as x-stamplay-jwt; since we are using the SDK we need not worry about including this token in our requests to Stamplay; but if you elect to use the Stamplay REST API, you need to include the x-stamplay-jwt in the x-stamplay-jwt header of each request that requires a user to be signed in.

To get started on the user management portion of our app, in our login.html, create a login and a register form.

Now that we have our forms ready, let’s initialize our app inside the main.js file.

Adding Logic To Manage Users

At the top of our main.js file: Initialize the SDK in our app with:

Stamplay.init("<yourAppId>");

Create a variable named user that contains the Stamplay User Model;

After we have initialize the Stamplay SDK and the user model, we will create four methods to manage our users.

Register

Add an event listener to the form element with an id equal to signupForm that will register a user on the submit event of the element. The Stamplay.User.signup() method at the top of our main.js file will take an object with a minimum of a email and password properties.

Login

Add an event listener to the form element with an id equal to loginForm that will create a user session from the form credentials from said form, when the login form submit event is emitted. The Stamplay.User.login() method, also takes an object with the email & password password credentials to the login method.

For logging out a user, add an event listener to an element with an id equal to logout that will end a user session when the logout button is clicked. To end the user session, just call the Stamplay.User.logout().

User Status

On document ready, retrieve the instance of the user currently logged in.

To get the currently logged in user, call the Stamplay.User.currentUser() method on the SDK.

Inside our main.js we will set event listeners to grab the input for the corresponding function and call the method action we desire to be fired on the event we are listening for.

To test our app locally, enter the test command: stamplay start, and visit localhost:8080 to debug. Next we will add functionality to allow a user to add posts, upvote posts, and add comments to posts.

App Utilities

Throughout our app we will be using functionality such as formatting dates, parsing through url parameters, rendering data driven templates and separating the hostname from the full post url. To keep DRY, and focus on the important ports, lets create a few utilities to help these operations go more smoothly before we dive into creating posts.

Inside your, create these functions from utils.js to use later inside our main.js file.

Creating Posts

To create a new post we can take an object modeled after the schema(what we created eariler in the editor for post) and pass it to the save() method on the SDK.

The steps to saving a new post are:

  • Assemble an object modeled after the post schema.
  • Call Stamplay.Object("post").save(myPost) to save the object as a post.

Inside our main.js we will set an event listener to grab the input, set each property on our ‘post’ model and call the save method on the model instance.

It is important to note that all asynchronous methods within the Stamplay JavaScript SDK return a promise. Each method’s promise is named then which takes a pair of callbacks.

  • The first is called when a promise resolves.
  • The second is called when a promise is rejected.

These promises are also chainable, resolving in the order chained.

When the form above is submitted our post will be saved, and be added to the Algolia Index.

All we are responsible for is saving the post to Stamplay, then the Stamplay task we set up will manage the task of indexing the post on Algolia.

Remember, to test locally, run the stamplay start command in your project directory and navigate to localhost:8080 to debug.

Viewing All Posts & Individual Posts

To fetch posts, we can use the get method on the Stamplay JavaScript SDK.

Stamplay.Object.get() will return the first 20 posts. Since we only want to view 10 at a time, and be able to paginate in the future we will setup query params to pass into the get() method to filter, sort, and paginate our posts.

Configuring Query Params

To filter, and sort out the posts that we retrieve we will set multiple checks to change which query param is used in our getSortedPostList function invocation.

To filter, and posts based on our location, and action we have configured the following functionality:

  • If we are on the item page, we will retrieve just the post details for the id passed in.
  • If there is url param newest we set the query param sort property to -dt_create.
  • This will return the posts in the order they were created.
  • If search is found within the url, we set queryParam._id to equal the id parameter passed into the url.

We attach an event listener to an anchor with the id equal to morenews, that when clicked increments the page queryParam value by one, returning the next set of posts per page to our view.

main.js - queryParam


var page_param = (Utils.getParameterByName('page') === "") ?  1 : Utils.getParameterByName('page');

var queryParam = {
  sort: '-actions.votes.total',
  per_page: 10,
  page: 1,
};


if (window.location.href.indexOf("item") > -1) {
  getPostDetail();
} else if (window.location.href.indexOf("newest") > -1) {
  queryParam.sort = '-dt_create';
} else if (window.location.href.indexOf("search") > -1) {
  var _id = Utils.getParameterByName("id");
  queryParam._id = _id;
}

getSortedPostList(queryParam);
$('#newest').css('font-weight', 'none');

$("#morenews").on("click", function(event) {
  event.preventDefault();
  queryParam.page += 1;
  getSortedPostList(queryParam);
})




main.js - getSortedPostList

function getSortedPostList(queryParam) {

  Stamplay.Object("post").get(queryParam)
  .then(function(res) {
    var viewDataArray = [];
    var post_count = (queryParam.page - 1) * queryParam.per_page;
    $('#newstable').html('');
    res.data.forEach(function (post, count) {
      var viewData = {
        id: post._id,
        count : post_count += 1,
        url: post.url,
        shortUrl: Utils.getHostname(post.url),
        title: post.title,
        dt_create: Utils.formatDate(post.dt_create),
        commentLength: post.actions.comments.length,
        votesLength: post.actions.votes.users_upvote.length
      }
      viewDataArray.push(viewData)
    });
    Utils.renderTemplate('list-elem', viewDataArray, '#newstable');

  })
}

Inside the resolve callback of our promise, we iterate through each post on the post set in the response. This is where we will display the data, and link up the up votes for our users to interact with.

When we view, a single post, we can run the getPostDetail function defined below to retrieve the details about that particular post.

main.js - getPostDetail

function getPostDetail() {
  var postId = Utils.getParameterByName("id");

  Stamplay.Object("post").get({ _id : postId})
  .then(function(res) {
    var post = res.data[0];
    var viewData = {
      id : post._id,
      url : post.url,
      shortUrl : Utils.getHostname(post.url),
      title : post.title,
      dt_create : Utils.formatDate(post.dt_create),
      votesLength : post.actions.votes.users_upvote.length
    }
    Utils.renderTemplate('post-detail', viewData, '#postcontent');

    post.actions.comments.forEach(function (comment) {
      var viewData = {
        displayName: comment.displayName,
        dt_create: Utils.formatDate(comment.dt_create),
        text: comment.text
      }
      Utils.renderTemplate('post-comment', viewData, '#postcomments');
    })

  }).catch(function (err) {
    console.log('error', err);
  })
}

Adding Comments & Upvotes

Next we will add comments, and upvotes to our post. First we will need access to the id of whichever post we are commenting on.

Once we retrieve the post we wish to comment on, which we may do by calling the fetch method on our post instance, passing in the id of the desired post to view.

To upvote a post, pass in the post _id to the Stamplay.Object("post).upVote(postId) method.

To add a comment to our post, pass in post id and the comment text to the Stamplay.Object("post).comment(postId, commentText) method.

Typeahead Search & Algolia

With typeahead and algolia, we will be able to search through the data on Stamplay, and return a list of items match your search.

Inside our main.js we setup the typeahead function to query algolia when we type a query into the search form inside our index.html. As we type, any matches to our current search will populate the suggestion field, providing our users a way to find content that matters to them without having to look through each post.

Deploy!

Now that we have used the various SDK methods to implement our app’s features, let's go live!

To deploy you stamplay app, type the stamplay deploy command at your project's root directory.

Add a comment when prompted for the deploy version, and your app will be live at: <yourappid>.stamplayapp.com.

Stamplay offers a huge range of functionality with just a few lines of code, it lets the developer focus on making its app unique, skipping the parts that are somewhat patternized in development. If you prefer a more manual interaction with the services Stamplay provides, you may use the full featured REST API. For more information about the REST API, visit the documentation.

Don’t forget, Stackshare users can try it now for free and benefit of an exclusive coupon, STAMPLAY_<3_STACKSHARE to get 6 months free of Plus plan if they sign up before Sept 30th, 2015!

Stamplay
API Lego for developers. Code less. Build more.
Tools mentioned in article