In this tutorial, you’ll learn how to authenticate and connect to the Twitter API using Node.js and Angular 6. By the end of this tutorial, you’ll have done the following:
- authenticate with the Twitter API
- post tweets with the Twitter API
- read the Twitter timeline with the Twitter API
- and more!
Create a Node Server
We will start by building a Node server which will handle interaction with the Twitter API. The first step will be to register a new app so as to obtain the credentials to start using the Twitter API.
Simply go to https://apps.twitter.com/, create a new app, and fill out all the necessary details—i.e. the app name, description, and URL. After creating your application, you will be required to create unique keys for your application. To do that, simply go to the Keys and Access Token tab and click on the Create my access token button located at the bottom of the page.
The application will generate four keys as follows:
- Consumer Key (the API key)
- Consumer Secret (the API secret)
- Access Token
- Access Token Secret
Please make note of the above keys as they will come in handy later on.
Create a directory for the server code, create a .json file by running npm init
, and create a server.js file.
mkdir server cd server npm init touch server.js
We will then install the twit
package and the rest of the dependencies necessary to bootstrap an Express application.
npm install twit body-parser cors express
The twit
package will help us in interacting with the Twitter API. Next, in server.js, initialize the modules, create an Express app, and launch the server.
const express = require('express'); const Twitter = require('twit'); const app = express(); app.listen(3000, () => console.log('Server running'))
Authentication
We will then supply the API keys to the twit
package as shown below.
const api-client = new Twitter({ consumer_key: 'CONSUMER_KEY', consumer_secret: 'CONSUMER_SECRET', access_token: 'ACCESS_TOKEN', access_token_secret: 'ACCESS_TOKEN_SECRET' });
The keys are unique to your application and are linked to your Twitter account. So when you make a request with the Twitter API, you will be the authorized user.
We will then create the endpoints for posting and retrieving tweets on our Node server.
Twitter provides the following endpoints that will enable us to interact with our Twitter timeline when retrieving and posting tweets.
- GET
statuses/home_timeline
—returns the most recent tweets posted by the user and the users they follow - GET
statuses/home_timeline
—returns the most recent mentions for the authenticating user - POST
statuses/update
—used for posting tweets
Retrieving Tweets
This first endpoint will be used to retrieve the latest tweets on your timeline. We’ll also specify the number of tweets we want to retrieve.
app.get('/home_timeline', (req, res) => { const params = { tweet_mode: 'extended', count: 10 }; client .get(`statuses/home_timeline`, params) .then(timeline => { res.send(timeline); }) .catch(error => { res.send(error); }); });
Next is the API for retrieving all the tweets where the authenticating user has been mentioned.
app.get('/mentions_timeline', (req, res) => { const params = { tweet_mode: 'extended', count: 10 }; client .get(`statuses/mentions_timeline`, params) .then(timeline => { res.send(timeline); }) .catch(error => { res.send(error); }); });
In order to be able to write to the Twitter timeline, we need to change the app Access permissions level to Read and write as shown below.
Posting Tweets
Next, update the server.js file to call the API for posting tweets.
app.post('/post_tweet', (req, res) => { tweet = req.body; client .post(`statuses/update`, tweet) .then(tweeting => { console.log(tweeting); res.send(tweeting); }) .catch(error => { res.send(error); }); });
We are now done with the node server, and you can now test your REST API with Postman to ensure it is working right.
Testing the Back-End
If you query the home_timeline
endpoint in your API, you should see something like the following.
And here is a GET request to the mentions_timeline
endpoint:
The server code we have created above can also be used to create a Twitter bot. Below is an example of a basic Twitter bot that updates a user’s status.
const express = require('express'); const Twitter = require('twit'); const app = express(); const client = new Twitter({ consumer_key: 'Consumer Key Here', consumer_secret: 'Consumer Secret Here', access_token: 'Access Token Here', access_token_secret: 'Token Secret Here' }); app.use(require('cors')()); app.use(require('body-parser').json()); app.post('/post_tweet', (req, res) => { tweet = {status:"Hello world"}; client .post(`statuses/update`, tweet) .then(timeline => { console.log(timeline); res.send(timeline); }) .catch(error => { res.send(error); }); }); app.listen(3000, () => console.log('Server running'));
Build an Angular App to Consume the REST APIs
We will now start building our Angular application which will consume the APIs from our Node server.
First, create an Angular application.
ng new client
Twitter Service
We will start by creating a Twitter service that will make requests to the Node server. Issue the following command in the Angular application.
ng generate service twitterservice
This will create two files, twitter.service.ts and twitter.service.spec.ts. Open twitter.service.ts, add the required imports, declare the API endpoint, and inject the HttpClient
module in the constructor.
api_url = 'http://localhost:3000'; constructor(private http: HttpClient) { }
We will then define the functions for consuming the REST API.
export class TwitterService { api_url = 'http://localhost:3000'; constructor(private http: HttpClient) { } getTimeline() { return this.http .get<any[]>(this.api_url+'/home_timeline') .pipe(map(data => data)); } getMentions() { return this.http .get<any[]>(this.api_url+'/mentions_timeline') .pipe(map(data => data)); } }
Access the Twitter Service from Component.
In order to access the Twitter service from our component, we will need to generate the following components.
ng generate component twitter_timeline ng generate component twitter_mentions ng generate component tweet
Next, declare the routes for the generated components in app.module.ts.
import { RouterModule, Routes } from '@angular/router'; const appRoutes: Routes = [ { path: 'twitter_timeline', component: TwitterTimelineComponent }, { path: 'twitter_mentions', component: TwitterMentionsComponent }, { path: 'tweets', component: TweetComponent }, { path: '', redirectTo: '', pathMatch: 'full' } ];
Now open app.component.html and render the components as shown below.
<mat-toolbar color="primary"> <mat-toolbar-row> <!-- <span>HOME</span> --> <span><a href="/">HOME</a></span> <span class="spacer"></span> <span mat-button routerLink="/twitter_timeline">Timeline</span> <br> <a mat-button routerLink="/twitter_mentions">Mentions</a> <br> <a mat-button routerLink="/tweets">Tweets</a> </mat-toolbar-row> </mat-toolbar> <router-outlet></router-outlet>
Retrieving Tweets
We’ll create two components for displaying our tweets. The TwitterTimelineComponent
will display the most recent tweets from the timeline of the authenticated user, while the TwitterMentionsComponent
will display all the tweets in which the authenticated user has been mentioned.
We will start with the TwitterTimelineComponent
. Update twitter-timeline.component.ts as follows:
export class TwitterTimelineComponent implements OnInit { myTimeline: any; constructor(private api: TwitterService) { } ngOnInit() { this.getTwitterTimeline(); } getTwitterTimeline(): void { this.api.getTimeline() .subscribe( myTimeline => { this.myTimeline = myTimeline; console.log(this.myTimeline); } ) } }
The getTwitterTimeline
method uses the TwitterService
to pull data from the authenticated users timeline. We then update twitter-timeline.component.html as shown below.
<h1>Tweeter Timeline</h1> <div *ngIf="undefined === myData">Loading...</div> <div *ngIf="undefined !== myData"> <div class ="card"> <ng-container *ngFor="let tweets of myData.data"> <h3>{{tweets.full_text }} </h3> <p>{{tweets.created_at}}</p> <p>{{tweets.user.name}}</p> <p>{{tweets.user.screen_name}}</p> <p>{{tweets.user.location}}</p> <p>{{tweets.user.description}}</p> </ng-container> </div> </div>
Here, we iterate through the array returned by the getTwitterTimeline
method and display the following attributes for each tweet:
location
description
username
created_at
screen_name
We then move on to the TwitterMentionsComponent and update it as follows.
export class TwitterMentionsComponent implements OnInit { myMentions: any; constructor(private api: TwitterService) { } ngOnInit() { this.getTwitterMentions(); } getTwitterMentions(): void { this.api.getTimeline() .subscribe( myMentions => { this.myMentions = myMentions; console.log(this.myMentions); } ) } }
Lastly, we need to display the data from the API in the template. Update twitter-mentions.component.html as follows:
<h1>Tweeter Mentions</h1> <div *ngIf="undefined === myData">Loading...</div> <div *ngIf="undefined !== myData"> <div class ="card"> <ng-container *ngFor="let tweets of myData.data"> <h3>{{tweets.full_text }} </h3> <p>{{tweets.created_at}}</p> <p>{{tweets.user.name}}</p> <p>{{tweets.user.screen_name}}</p> <p>{{tweets.user.location}}</p> <p>{{tweets.user.description}}</p> </ng-container> </div> </div>
Now, when you run the app, you should see all the attributes of your tweets displayed.
Posting Tweets
We will start with the form for posting data to the /post_tweet
endpoint, where we define an input field and a submit button for posting tweets. We will use the FormBuilder
module to build our status update form. Add the following code to tweet.component.ts.
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; export class TweetComponent implements OnInit { tweetForm: FormGroup; constructor(private api: TwitterService private formBuilder: FormBuilder) { } ngOnInit() { this.tweetForm = this.formBuilder.group({ tweetdata: ['', Validators.required] }); } }
Now update the template so that Angular knows which form to use.
<mat-card class="contact-card"> <mat-card-content> <form [formGroup]="tweetForm" (ngSubmit)="onSubmit()"> <mat-form-field> <input matInput placeholder="Status" formControlName="tweetdata" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.tweetdata.errors }" > </mat-form-field> <br> <div class="form-group"> <button [disabled]="loading" class="btn btn-primary">TWEET</button> <img *ngIf="loading" src="https://media.giphy.com/media/3oEjI6SIIHBdRxXI40/giphy.gif" /> </div> </form> </mat-card-content> </mat-card>
As you can see above, we have added validators so that the form cannot be submitted if it is blank.
We then go on to the Twitter service and update it to include the code for posting data to the API.
tweet(tweetdata: string) { return this.http.post<any>(`${this.api_url}/post_tweet/`, { status: tweetdata}) .pipe(map(tweet => { alert("tweet posted") return tweet; })); } }
We will then update the TweetComponent
to feature the code for calling the method for posting to the Twitter API. Add the following to tweet.component.ts.
export class TweetComponent implements OnInit { tweetForm: FormGroup; loading = false; submitted = false; returnUrl: string; error = ''; constructor(private api: TwitterService private formBuilder: FormBuilder) { } ngOnInit() { this.tweetForm = this.formBuilder.group({ tweetdata: ['', Validators.required] }); } get f() { return this.tweetForm.controls; } onSubmit() { this.submitted = true; // stop here if form is invalid if (this.tweetForm.invalid) { return; } this.loading = true; this.api.tweet(this.f.tweetdata.value) .pipe(first()) .subscribe( data => { console.log("yes") }, error => { this.error = error; this.loading = false; }); } }
You should now be able to retrieve the latest tweets by hitting the /home_timeline
endpoint, retrieve your mentions via the /mentions_timeline
endpoint, and post tweets via the /post_tweet
endpoint.
Source:: Net Tuts