Categories
JavaScript Nodejs

How to Use Sequelize to Manipulate Databases

Sequelize is a Node.js ORM with which has one of the most comprehensive features sets available.

It is similar to other ORMs like ActiveRecord, in that they are based on creating migrations with the Sequelize CLI, allowing you to write code to modify your database’s structure.

However, there are a few catches which someone has to be aware of. The migration functionality is not as smart as ActiveRecord. You cannot roll back database migration withour creating a down migration.

Also, migrations are not transactions, which means it may fail with a partially run migration where some parts of it failed to execute, leaving you with some changes made, but others not.

Sequelize CLI has to be installed separately from the library. You can run npm run --save-dev sequelize-cli to install it. After that, run npx sequelize model:generate to create your first model with its associated migration.

Add Model with Migration

For example, to create a User model with a Users table, run:

$ npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string

You may have to have administrator privileges in Windows to run this. This will create a firstName field, a lastName field, and an email field in the User model and when npx sequelize-cli migration is run, then a Users table will be created with the columns firstName , lastName and email .

The migration file should have this code:

'use strict';

module.exports = {  
  up: (queryInterface, Sequelize) => {  
    return queryInterface.createTable('Users', {  
      id: {   
        allowNull: false,  
        autoIncrement: true,  
        primaryKey: true,  
        type: Sequelize.INTEGER  
      },  
      firstName: {  
        type: Sequelize.STRING  
      },  
      email: {  
        type: Sequelize.STRING  
      },  
    });  
   }, down: (queryInterface, Sequelize) => {  
     return queryInterface.dropTable('Users');  
   }  
};

Note the id column is created automatically, and there is a down migration in the down function where the reverse of the up migration is included. If the code in the down function is not included, then you cannot run npx sequelize-cli db:migrate:undo to undo your migration.

You can also create migration and model files separately. They will be linked together if they are named in the correct pattern. Table name should be plural of the model name. For example Users table will map to the User model. To create migration without its associated mode, run npx sequelize migration:generate .

If you have multiple operations, you have to wrap them in an array and pass the array of operations into Promise.all and return that, since the return value of the up and down functions is a promise.

Adding Constraints

Adding constraints is simple. To do this, put the following in the up function of your migration file.

queryInterface.addConstraint(  
  "Users",  
  \["email"\],  
  {  
    type: "unique",  
    name: "emailUnique"  
})

To drop this, put:

queryInterface.removeConstraint(  
  'Users',  
  'emailUnique'  
)

Associations

To make has one, has many or many to many relations between tables, you can specify that using the Model.associate function. For example, if you have a Tweets table where multiple Tweets belong to one User , you can do:

Tweet.associate = function (models) { Tweet.belongsTo(models.User, {  
    foreignKey: 'userId',  
    targetKey: 'id'  
  });  
};

foreignKey is the ID referencing the external table and targetKey is the ID column of the table you’re referencing.

And in the User model:

User.associate = function (models) {  
  User.hasMany(models.Tweet, {  
    foreignKey: 'userId',  
    sourceKey: 'id'  
  });  
};

foreignKey is the ID referencing the current table in this case and sourceKey is the ID column of the table you’re referencing.

This specifies that each User has many Tweets.

Similarly, you can replace hasMany with hasOne to specifiy one to one relationship.

To make a many to many relationship, you need a join table between the 2 tables that you want to create relationship with, then you can use belongsToMany function of your model to create the relationship. You need this in both of your tables that you are creating the relationship with.

For example if multiple Users can belong in multiple ChatRooms , then do:

User.associate = function(models) {        
  User.belongsToMany(models.ChatRoom, {      
    through: 'UserChatRooms',      
    as: 'chatrooms',      
    foreignKey: 'userId',      
    otherKey: 'chatRoomId'    
  });  
};

And for the ChatRoom model:

ChatRoom.associate = function(models) {        
  ChatRoom.belongsToMany(models.User, {      
    through: 'UserChatRooms',      
    as: 'users',      
    foreignKey: 'chatRoomId',      
    otherKey: 'userId'    
  });  
};

foreingKey is the ID that the other table references, otherKey is the key that is in the current table.

Changing Columns

You can rename a column like this:

queryInterface.renameColumn('Tweets', 'content', 'contents')

The first argument is the table name, second is the original column, third one is the new column name.

Changing data type is simple:

queryInterface.changeColumn(   
  'Tweets',  
  'scheduleDate', {  
    type: Sequelize.STRING  
  }  
)

If you want to change string to date or time, do:

queryInterface.changeColumn(  
  'Tweets',   
  'scheduleDate', {  
    type: 'DATE USING CAST("scheduleDate" as DATE)'  
  }  
)queryInterface.changeColumn(  
  'Tweets',  
  'scheduleTime', {  
     type: 'TIME USING CAST("scheduleTime" as TIME)'  
  }  
)

To run migrations, run npx sequelize db:migrate .

And there we have it — a brief look into how to use Sequelize to manipulate databases! 🎉

Categories
JavaScript Nodejs

How to Incorporate Twitter Functionality into Your Node.js App

If you incorporated Twitter sign in functionality according to https://medium.com/@hohanga/how-to-add-twitter-sign-in-to-your-node-js-back-end-with-angular-app-as-the-front-end-d90213f95703, then it is very easy to incorporate Twitter functionality into your app by calling the Twitter API. To get the consumer key and secret, and find out how to get the OAuth access token and secret from Twitter which you will use with the Twitter API, follow https://medium.com/@hohanga/how-to-add-twitter-sign-in-to-your-node-js-back-end-with-angular-app-as-the-front-end-d90213f95703

Once you have the OAuth access token and secret, calling Twitter API is a piece of cake. For Node.js, I had success with https://www.npmjs.com/package/twit.

You simply pass in whatever credentials are requested to build the Twit object, which allows you to call the Twitter API.

Once that is done, you can do many things which otherwise has to be done manually.

According to https://www.npmjs.com/package/twit, here are the endpoints that it can call:

  • GET ‘statuses/update’
  • GET ‘search/tweets’
  • GET ‘followers/ids’
  • GET ‘account/verify_credentials’
  • POST ‘statuses/retweet/:id’
  • POST ‘statuses/destroy/:id’
  • GET ‘users/suggestions/:slug’
  • POST ‘media/upload’
  • ‘media/metadata/create’
  • ‘statuses/filter’

All the basic functionality like tweeting, uploading photos, and streaming can be used with this library, which means that you can automate tweeting and getting data from your account.

The full list of endpoints are at https://developer.twitter.com/en.html

Categories
JavaScript Nodejs

How to Add Twitter Sign In to Your Node.js Back End

Twitter uses the standard OAuth for authentication, which means you incorporate a standardized way of logging in if you use Twitter sign in.

In Node.js, it is very easy to add Twitter sign in to an Express web app.


Getting Started

First, you have to make an Express app. Express is a routing library with a lot of add-ons built for easy web development.

There are many Express app boilerplates available on the web. There is also an Express code generator from the makers of the Express framework.

Using the latest Node.js versions, you can run npx express-generator.

If npx is not available, you can install express-generator globally and run that:

$ npm install -g express-generator  
$ express

Make a folder for your project and follow the instructions.

To make the example simple, this app will provide the redirect URL that you get after providing the consumer key and request token for the Angular app.

Then, after the user goes through the Twitter sign in, it will redirect back to the Angular app, which will then call the Express API to save the OAuth access token and the OAuth access token secret to a database.

We need to make an entry point file for Express.

We need to install express-session, express-logger, cookie-parser, and cors for saving sessions, logging, parsing cookies, and allowing external requests for our Angular app, respectively.

babel-register and bale-polyfill are required to use the latest JavaScript features in our Node.js web app.

To save the secrets, use the [dotenv](https://www.npmjs.com/package/dotenv) library. With this, the secrets will be read from the .env file, rather than hard coding them into the code, which is very bad secret practice.

To get the Twitter keys, you have to apply for a developer account at https://developer.twitter.com/. You will then get the keys and secrets required, which you will put into the .env file.

The .env file should be a key-value list, like this:

TWITTER_CONSUMER_KEY=''  
TWITTER_CONSUMER_SECRET=''  
TWITTER_CALLBACK_URL='http://localhost:4200/settings'
SESSION_SECRET=''

I will call the entry point file app.js .

To run this, go to your project folder and run node app.js:

Then, we need the oauth library to make an oauth.OAuth object which will allow the Express app to get the request token and request token secret.

Add a controllers folder in the same level as app.js.

Then, add sessionsController.js into the controllers folder.

Add the following to sessionsController.js:

The connect route will send the Twitter sign-in URL as the redirect URL.

Then, the Angular app will call the saveAccessTokens route to store the OAuth access token and its secret in the session.


Angular CLI

To build the Angular app, you need the Angular CLI.

To install it, run npm i -g @angular/cli in your Node.js command prompt. Then, run ng new frontend to generate the skeleton code for your front end app.

Also, install @angular/material according to the Angular documentation.

After that, replace the default app.module.ts with the following:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {
  MatButtonModule,
  MatTableModule,
  MAT_DIALOG_DEFAULT_OPTIONS,
} from '@angular/material';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { SettingsPageComponent } from './settings-page/settings-page.component';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { SessionService } from './session.service';
import { HttpReqInterceptor } from './http-req-interceptor';
@NgModule({
  declarations: [
    AppComponent,
    SettingsPageComponent,
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatButtonModule,
    FormsModule,
    HttpClientModule,
  ],
  providers: [
    SessionService,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: HttpReqInterceptor,
      multi: true
    },
    UserService,
    TweetsService,
  ],
  bootstrap: [AppComponent],
})
export class AppModule { }

We need to use Angular’s HTTP client to connect to our Express routes to get the redirect URL and get the access token from the redirect after logging in with Twitter, then send it back to our route.

To do this, run ng g service session.

This will create session.service.ts:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from 'src/environments/environment';
@Injectable({
  providedIn: 'root'
})
export class SessionService {
  constructor(private http: HttpClient) { }
  getRedirectUrl() {
  return this.http.get(`${environment.apiUrl}/sessions/connect`)
}
  saveAccessToken(oauthToken: string, oauthVerifier: string) {
    return this.http.get(`${environment.apiUrl}/sessions/saveAccessTokens?oauth_token=${oauthToken}&oauth_verifier=${oauthVerifier}`)
  }
}

In here, environment.apiUrl is the URL to our API, which is specified in environment.ts.

Now, we need a page with a button that calls our Express route to get the redirect URL.

Run ng g component settingsPage to create settings-page.component.ts and settings-page.component.html, which is where the button will be placed.

Add the following to settings-page.component.html:

<div>  
  <button mat-raised-button (click)='redirectToTwitter()'>Connect to Twitter Account</button>  
</div>

Then, add the following settings-page.component.ts:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { SessionService } from '../session.service';
@Component({
  selector: 'app-settings-page',
  templateUrl: './settings-page.component.html',
  styleUrls: ['./settings-page.component.scss']
})
export class SettingsPageComponent implements OnInit {
  constructor(
    private activatedRoute: ActivatedRoute,
    private sessionService: SessionService,
  ) {
    this.activatedRoute.queryParams.subscribe(params => {
      const oauthVerifier = params['oauth_verifier'];
      const oauthToken = params['oauth_token'];
      if (oauthToken && oauthVerifier) {
        this.saveAccessToken(oauthToken, oauthVerifier);
      }
    });
  }
  ngOnInit() {}
  saveAccessToken(oauthToken: string, oauthVerifier: string) {
    this.sessionService.saveAccessToken(oauthToken, oauthVerifier).subscribe(res => {
    alert('Token saved');
    })
  }
  redirectToTwitter() {
    this.sessionService.getRedirectUrl().subscribe((res: any) => {
      location.href = res.redirectUrl;
    })
  }
}

After adding the code above, you get a button that, after you click it, will go to the Twitter sign-in page.

Then, once Twitter sign in succeeds, you will be redirected to the same page with the OAuth access token and verifier, which will be sent to our Express API and stored in the session.


Token Saved

You will get Token saved message once it succeeds.

In the end, this is the workflow you should get:

  1. First, you get the connect button:

https://thewebdev.info/wp-content/uploads/2020/05/connect.png

  1. Then, you are redirected to the Twitter login:

https://thewebdev.info/wp-content/uploads/2020/05/twitter-login.png

  1. Finally, you are redirected back with the OAuth access token and verifier, and with those, you get the access token and secret which will be stored to the session.

If that succeeds, the saveAccessTokens route will return a successful response, which will then trigger the Angular app to alert Token saved.