This article was originally published on the Okta developer blog. Thank you for supporting the partners who make SitePoint possible.
In recent years, single page applications (SPAs) have become more and more popular. A SPA is a website that consists of just one page. That lone page acts as a container for a JavaScript application. The JavaScript is responsible for obtaining the content and rendering it within the container. The content is typically obtained from a web service and RESTful APIs have become the go-to choice in many situations. The part of the application making up the SPA is commonly known as the client or front-end, while the part responsible for the REST API is known as the server or back-end. In this tutorial, you will be developing a simple Angular single page app with a REST backend, based on Node and Express.
You’ll be using Angular as it follows the MVC pattern and cleanly separates the View from the Models. It is straightforward to create HTML templates that are dynamically filled with data and automatically updated whenever the data changes. I have come to love this framework because it is very powerful, has a huge community and excellent documentation.
For the server, you will be using Node with Express. Express is a framework that makes it easy to create REST APIs by allowing to define code that runs for different requests on the server. Additional services can be plugged in globally, or depending on the request. There are a number of frameworks that build on top of Express and automate the task of turning your database models into an API. This tutorial will not make use of any of these in order to keep this focused.
Angular encourages the use of TypeScript. TypeScript adds typing information to JavaScript and, in my opinion, is the future of developing large scale applications in JavaScript. For this reason, you will be developing both client and server using TypeScript.
Here are the libraries you’ll be using for the client and the server:
- Angular: The framework used to build the client application
- Okta for Authorisation: A plugin that manages single sign-on authorization using Okta, both on the client and the server
- Angular Material: An angular plugin that provides out-of-the-box Material Design
- Node: The actual server running the JavaScript code
- Express: A routing library for responding to server requests and building REST APIs
- TypeORM: A database ORM library for TypeScript
Start Your Basic Angular Client Application
Let’s get started by implementing a basic client using Angular. The goal is to develop a product catalog which lets you manage products, their prices, and their stock levels. At the end of this section, you will have a simple application consisting of a top bar and two views, Home and Products. The Products view will not yet have any content and nothing will be password protected. This will be covered in the following sections.
To start you will need to install Angular. I will assume that you already have Node installed on your system and you can use the npm
command. Type the following command into a terminal.
npm install -g @angular/cli@7.0.2
Depending on your system, you might need to run this command using sudo
because it will install the package globally. The angular-cli
package provides the ng
command that is used to manage Angular applications. Once installed go to a directory of your choice and create your first Angular application using the following command.
ng new MyAngularClient
Using Angular 7, this will prompt you with two queries. The first asks you if you want to include routing. Answer yes to this. The second query relates to the type of style sheets you want to use. Leave this at the default CSS.
ng new
will create a new directory called MyAngularClient
and populate it with an application skeleton. Let’s take a bit of time to look at some of the files that the previous command created. At the src
directory of the app, you will find a file index.html
that is the main page of the application. It doesn’t contain much and simply plays the role of a container. You will also see a style.css
file. This contains the global style sheet that is applied throughout the application. If you browse through the folders you might notice a directory src/app
containing five files.
app-routing.module.ts
app.component.css
app.component.html
app.component.ts
app.component.spec.ts
app.module.ts
These files define the main application component that will be inserted into the index.html
. Here is a short description of each of the files:
app.component.css
file contains the style sheets of the mainapp
component. Styles can be defined locally for each componentapp.component.html
contains the HTML template of the componentapp.component.ts
file contains the code controlling the viewapp.module.ts
defines which modules your app will useapp-routing.module.ts
is set up to define the routes for your applicationapp.component.spec.ts
contains a skeleton for unit testing theapp
component
I will not be covering testing in this tutorial, but in real life applications, you should make use of this feature. Before you can get started, you will need to install a few more packages. These will help you to quickly create a nicely designed responsive layout. Navigate to the base directory of the client, MyAngularClient
, and type the following command.
npm i @angular/material@7.0.2 @angular/cdk@7.0.2 @angular/animations@7.0.1 @angular/flex-layout@7.0.0-beta.19
The @angular/material
and @angular/cdk
libraries provide components based on Google’s Material Design, @angular/animations
is used to provide smooth transitions, and @angular/flex-layout
gives you the tools to make your design responsive.
Next, create the HTML template for the app
component. Open src/app/app.component.html
and replace the content with the following.
<mat-toolbar color="primary" class="expanded-toolbar">
<button mat-button routerLink="/"></button>
<div fxLayout="row" fxShow="false" fxShow.gt-sm>
<button mat-button routerLink="/"><mat-icon>home</mat-icon></button>
<button mat-button routerLink="/products">Products</button>
<button mat-button *ngIf="!isAuthenticated" (click)="login()"> Login </button>
<button mat-button *ngIf="isAuthenticated" (click)="logout()"> Logout </button>
</div>
<button mat-button [mat-menu-trigger-for]="menu" fxHide="false" fxHide.gt-sm>
<mat-icon>menu</mat-icon>
</button>
</mat-toolbar>
<mat-menu x-position="before" #menu="matMenu">
<button mat-menu-item routerLink="/"><mat-icon>home</mat-icon> Home</button>
<button mat-menu-item routerLink="/products">Products</button>;
<button mat-menu-item *ngIf="!isAuthenticated" (click)="login()"> Login </button>
<button mat-menu-item *ngIf="isAuthenticated" (click)="logout()"> Logout </button>
</mat-menu>
<router-outlet></router-outlet>
The mat-toolbar
contains the material design toolbar, whereas router-outlet
is the container that will be filled by the router. The app.component.ts
file should be edited to contain the following.
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
public title = 'My Angular App';
public isAuthenticated: boolean;
constructor() {
this.isAuthenticated = false;
}
login() {
}
logout() {
}
}
This is the controller for the app
component. You can see that it contains a property called isAuthenticated
together with two methods login
and logout
. At the moment these don’t do anything. They will be implemented in the next section which covers user authentication with Okta. Now define all the modules you will be using. Replace the contents of app.module.ts
with the code below:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FlexLayoutModule } from '@angular/flex-layout';
import {
MatButtonModule,
MatDividerModule,
MatIconModule,
MatMenuModule,
MatProgressSpinnerModule,
MatTableModule,
MatToolbarModule
} from '@angular/material';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
AppRoutingModule,
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
FlexLayoutModule,
MatToolbarModule,
MatMenuModule,
MatIconModule,
MatButtonModule,
MatTableModule,
MatDividerModule,
MatProgressSpinnerModule,
FormsModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Notice all the material design modules. The @angular/material
library requires you to import a module for each type of component you wish to use in your app. Starting with Angular 7, the default application skeleton contains a separate file called app-routing.module.ts
. Edit this to declare the following routes.
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ProductsComponent } from './products/products.component';
import { HomeComponent } from './home/home.component';
const routes: Routes = [
{
path: '',
component: HomeComponent
},
{
path: 'products',
component: ProductsComponent
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
This defines two routes corresponding to the root path and to the products
path. It also attaches the HomeComponent
and the ProductsComponent
to these routes. Create these components now. In the base directory of the Angular client, type the following commands.
ng generate component Products
ng generate component Home
This creates html
, css
, ts
, and spec.ts
files for each component. It also updates app.module.ts
to declare the new components. Open up home.component.html
in the src/app/home
directory and paste the following content.
<div class="hero">
<div>
<h1>Hello World</h1>
<p class="lead">This is the homepage of your Angular app</p>
</div>
</div>
Include some styling in the home.component.css
file too.
.hero {
text-align: center;
height: 90vh;
display: flex;
flex-direction: column;
justify-content: center;
font-family: sans-serif;
}
Leave the ProductsComponent
empty for now. This will be implemented once you have created the back-end REST server and are able to fill it with some data. To make everything look beautiful only two little tasks remain. Copy the following styles into src/style.css
@import "~@angular/material/prebuilt-themes/deeppurple-amber.css";
body {
margin: 0;
font-family: sans-serif;
}
.expanded-toolbar {
justify-content: space-between;
}
h1 {
text-align: center;
}
Finally, in order to render the Material Design Icons, add one line inside the <head>
tags of the index.html
file.
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
You are now ready to fire up the Angular server and see what you have achieved so far. In the base directory of the client app, type the following command.
ng serve
Then open your browser and navigate to http://localhost:4200
.
Add Authentication to Your Node + Angular App
If you have ever developed web applications from scratch you will know how much work is involved just to allow users to register, verify, log on and log out of your application. Using Okta this process can be greatly simplified. To start off, you will need a developer account with Okta.
In your browser, navigate to developer.okta.com and click on Create Free Account and enter your details.
Once you are done you will be taken to your developer dashboard. Click on the Add Application button to create a new application.
Start by creating a new single page application. Choose Single Page App and click Next.
On the next page, you will need to edit the default settings. Make sure that the port number is 4200. This is the default port for Angular applications.
That’s it. You should now see a Client ID which you will need to paste into your TypeScript code.
To implement authentication into the client, install the Okta library for Angular.
npm install @okta/okta-angular@1.0.7 --save-exact
In app.module.ts
import the OktaAuthModule
.
import { OktaAuthModule } from '@okta/okta-angular';
In the list of imports
of the app
module, add:
OktaAuthModule.initAuth({
issuer: 'https://{yourOktaDomain}/oauth2/default',
redirectUri: 'http://localhost:4200/implicit/callback',
clientId: '{YourClientId}'
})
Here yourOktaDomain
should be replaced by the development domain you see in your browser when you navigate to your Okta dashboard. YourClientId
has to be replaced by the client ID that you obtained when registering your application. The code above makes the Okta Authentication Module available in your application. Use it in app.component.ts
, and import the service.
import { OktaAuthService } from '@okta/okta-angular';
Modify the constructor to inject the service and subscribe to it.
constructor(public oktaAuth: OktaAuthService) {
this.oktaAuth.$authenticationState.subscribe(
(isAuthenticated: boolean) => this.isAuthenticated = isAuthenticated
);
}
Now, any changes in the authentication status will be reflected in the isAuthenticated
property. You will still need to initialize it when the component is loaded. Create a ngOnInit
method and add implements OnInit
to your class definition
import { Component, OnInit } from '@angular/core';
...
export class AppComponent implements OnInit {
...
async ngOnInit() {
this.isAuthenticated = await this.oktaAuth.isAuthenticated();
}
}
Finally, implement the login
and logout
method to react to the user interface and log the user in or out.
login() {
this.oktaAuth.loginRedirect();
}
logout() {
this.oktaAuth.logout('/');
}
In the routing module, you need to register the route that will be used for the login request. Open app-routing.module.ts
and import OktaCallbackComponent
and OktaAuthGuard
.
import { OktaCallbackComponent, OktaAuthGuard } from '@okta/okta-angular';
Add another route to the routes
array.
{
path: 'implicit/callback',
component: OktaCallbackComponent
}
This will allow the user to log in using the Login button. To protect the Products
route from unauthorized access, add the following line to the products
route.
{
path: 'products',
component: ProductsComponent,
canActivate: [OktaAuthGuard]
}
That’s all there is to it. Now, when a user tries to access the Products view, they will be redirected to the Okta login page. Once logged on, the user will be redirected back to the Products view.
Implement a Node REST API
The next step is to implement a server based on Node and Express that will store product information. This will use a number of smaller libraries to make your life easier. To develop in TypeScript, you’ll need typescript
and tsc
. For the database abstraction layer, you will be using TypeORM. This is a convenient library that injects behavior into TypeScript classes and turns them into database models. Create a new directory to contain your server application, then run the following command in it.
npm init
Answer all the questions, then run:
npm install --save-exact express@4.16.4 @types/express@4.16.0 @okta/jwt-verifier@0.0.14 express-bearer-token@2.2.0 tsc@1.20150623.0 typescript@3.1.3 typeorm@0.2.8 sqlite3@4.0.3 cors@2.8.4 @types/cors@2.8.4
I will not cover all these libraries in detail, but you will see that @okta/jwt-verifier
is used to verify JSON Web Tokens and authenticate them.
In order to make TypeScript work, create a file tsconfig.json
and paste in the following content.
The post Build a Basic CRUD App with Angular and Node appeared first on SitePoint.
No comments:
Post a Comment