Wednesday, March 28, 2018

Building a Twitter Client with NodeJS and Angular

In this tutorial, we’re going to look at how to build a basic Twitter client with NodeJS, and an Angular application to display your home timeline of tweets. This is a rapid tour with things to consider while setting up your own Twitter client and Angular application.

First, we’re going to build a NodeJS server, which will handle communicating between the Twitter API and the Angular application. Then, we’ll build up the Angular application to display and interact with your Twitter timeline.

While you may be able to go through this tutorial without any prior NodeJS or Angular experience, I’ll assume some prior knowledge in the article.

Setting Up the Project

You’ll need a recent version of NodeJS set up on your machine. Then ensure you have the Angular CLI. The links provided give you a good place to start if you need help with either of those tasks.

The project source code can be found on GitHub. You can get it all running locally by either cloning it with Git or downloading the files from the repo’s GitHub archive.

git clone https://github.com/sitepoint-editors/twitter-angular-client

Once you have the files, from your terminal you’ll need to run npm install to get all of the dependencies installed. Then we can get to work!

Creating a Twitter Client in NodeJS

To access Twitter’s API, we need to register for a new “app”, which is essentially a way for Twitter to give us a set of credentials. These are unique for your application, so don’t share them publicly anywhere. You must, of course, have a Twitter account to access the data.

To start, go to https://apps.twitter.com/ and select Create New App. You can fill out the name, description, and website URL for your app. (You can use a fake URL for now. If you publish your app it should be your actual website.)

From there, you’ll see the new app page with your details. Go to the Keys and Access Tokens page, where you can see a button to Create my access token near the bottom. Click the button, and then you should see four values: Consumer Key (API Key), Consumer Secret (API Secret), Access Token, and Access Token Secret. We’ll use these in a moment, so be sure to keep this information handy.

Creating the Twitter Client in NodeJS

Now it’s time to dig into our NodeJS server, which will bridge the gap between Twitter’s API and the Angular app. In the project, you should see the server.js file, which you’ll need to open and tweak.

First, you’ll need to update the block that contains the credentials you received from the Twitter app earlier. You should copy those values into the block here. We’re using a Twitter package called Twit to help us connect to Twitter, though there are others available with various levels of functionality.

const client = new Twitter({
  consumer_key: 'CONSUMER_KEY',
  consumer_secret: 'CONSUMER_SECRET',
  access_token: 'ACCESS_TOKEN',
  access_token_secret: 'ACCESS_TOKEN_SECRET'
});

Now we should be able to connect to Twitter. We’re also using the popular ExpressJS to create and manage our server. Now that you have the credentials installed, you can run the server.

node server

Our next step is to make several routes that will handle the HTTP requests our Angular application will need to make to load the Twitter data. Our first route is to get the current user, and validate their credentials. The Access Token and Secret you provided are linked to your Twitter account, so you’ll be the authorized user in this case. When this route is called, it will call the Twitter account/verify_credentials endpoint and return an object containing your user data.

app.get('/api/user', (req, res) => {
  client.get('account/verify_credentials').then(user => {
    res.send(user)
  }).catch(error => {
    res.send(error);
  });
});

The next route we’ll create is to get your home timeline. It requests the statuses/home_timeline endpoint, and passes a few parameters to give us more of the data we need.

Due to rate limiting on the Twitter API, we’ve implemented a simple cache that will only request new data once a minute (which is the max rate before you receive errors). It basically keeps track of the last response and the time it was requested, only allowing new requests to Twitter to run after a minute. Rate limiting is a primary design consideration to have when building a Twitter app.

let cache = [];
let cacheAge = 0;

app.get('/api/home', (req, res) => {
  if (Date.now() - cacheAge > 60000) {
    cacheAge = Date.now();
    const params = { tweet_mode: 'extended', count: 200 };
    if (req.query.since) {
      params.since_id = req.query.since;
    }
    client
      .get(`statuses/home_timeline`, params)
      .then(timeline => {
        cache = timeline;
        res.send(timeline);
      })
      .catch(error => res.send(error));
  } else {
    res.send(cache);
  }
});

Finally, we create a set of routes to handle like/unlike and retweet/unretweet actions for a tweet. This will allow us not only to read data, but also take action. These will require that you’ve set the application Access Level to Read and write (in case you changed it in the Twitter app settings).

app.post('/api/favorite/:id', (req, res) => {
  const path = (req.body.state) ? 'create' : 'destroy';
  client
    .post(`favorites/${path}`, {id: req.params.id})
    .then(tweet => res.send(tweet))
    .catch(error => res.send(error));
});

app.post('/api/retweet/:id', (req, res) => {
  const path = (req.body.state) ? 'retweet' : 'unretweet';
  client
    .post(`statuses/retweet/${req.params.id}`)
    .then(tweet => res.send(tweet))
    .catch(error => res.send(error));
});

There are many Twitter APIs for engaging with Twitter data, but the fundamental rules remain the same. The only major issue here is we’ve hard-coded credentials to a single user, which you’d need in order to set up your own OAuth server (or use an existing one) to handle the authentication aspects, which you can learn more about on Twitter Authentication documentation.

Creating the Angular App

Now it’s time to turn our attention to the Angular application that uses the server we created. We’ll take a look at the key aspects of the application and how they work to create the final result. We’ve built this application using Clarity for the UI layer (it gives us many useful layout components), but otherwise everything is just Angular.

To run the Angular application, just run the following command and then open up http://localhost:4200:

ng serve

Inside of the application, we have a model at src/app/tweet.ts which contains the TypeScript interface that describes most of the properties of a tweet (some have been omitted). I believe it’s essential to describe your types properly for large-scale Angular applications as well as smaller ones, so this interface gives us the shape of a tweet.

Angular TwitterService

First, we’ll need a service that can make requests to our NodeJS server to get the latest tweets. In Angular, the HttpClient is the utility you use to make HTTP requests, so I’ve created an Angular service to encapsulate the logic for these calls. Open up src/app/twitter.service.ts and you’ll see the following code:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../environments/environment';
import { Tweet } from './tweet';

export interface TwitterResponse {
  data: any;
  resp: any;
}

@Injectable()
export class TwitterService {

  constructor(private http: HttpClient) { }

  user() {
    return this.http.get<TwitterResponse>(`${environment.api}/user`);
  }

  home(since?: string) {
    return this.http.get<TwitterResponse>(`${environment.api}/home?since=${since}`);
  }

  action(property: 'favorite'|'retweet', id: string, state: boolean) {
    return this.http.post<TwitterResponse>(`${environment.api}/${property}/${id}`, {state});
  }
}

This is a fairly basic service, which has methods to build a request for each API that we’ll support. The user method will return the current user (which will always be you). The home method will return the latest 200 tweets in your home timeline (or how ever many appeared since the last tweet specified). Finally, the action property handles making either a favorite or retweet call, by sending a boolean state value to toggle the status.

This service is generic, and each of these methods returns an Observable. If you want to learn more about them, you can read about Functional Reactive with RXJS, but the way they’re used here is similar to how a promise works. We’ll see how to use them in a moment.

Using the Angular TwitterService to load user

We’ll use the TwitterService in a few places, starting with loading the AppComponent. We’ll use it to load the user details (which appears in the top corner), and to load the list of tweets for the home page. Open up src/app/app.component.ts and you should see the following code:

import { Component , OnInit } from '@angular/core';
import { TwitterService } from './twitter.service';
import { Tweet } from './tweet';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  providers: [TwitterService]
})
export class AppComponent implements OnInit {
  user;

  constructor(private twitter: TwitterService) {}

  ngOnInit() {
    this.twitter.user().subscribe(user => this.user = user.data);
  }
}

The AppComponent does one main thing using our TwitterService. The ngOnInit method fires as soon as the component has initialized, and requests the user data. Here we’re using the Observable returned by the TwitterService.user method, and when we use subscribe it will trigger the actual HTTP request to fire. Once it’s returned, the callback function stores the user property, which is used to display content in the navbar. You can see the user property bindings in the component template below, such as user.profile_image_url_https:

<clr-main-container>
  <clr-header class="header-4">
    <div class="branding">
      <a class="nav-link">
        <div class="title">Twangular</div>
      </a>
    </div>
    <div class="header-actions" *ngIf="user">
      <a class="nav-link">
        <span class="nav-text">
          <img [src]="user.profile_image_url_https" class="avatar" />
          @
        </span>
      </a>
    </div>
  </clr-header>
  <div class="content-container">
    <main class="content-area">
      <app-tweets></app-tweets>
    </main>
  </div>
</clr-main-container>

Also, the use of <app-tweets></app-tweets> will insert the TweetsComponent, which handles the actual loading and display of tweets, so let’s take a look at it now.

Continue reading %Building a Twitter Client with NodeJS and Angular%


by Jeremy Wilken via SitePoint

No comments:

Post a Comment