Friday, May 03, 2019

Vanilla JavaScript for the Client Side of my JWT Server App

This is the Vanilla JavaScript client side code to accompany JWT on .NET Core 2.2 and Little Else. I have the sourcecode on my Github account as a branch of the other project.

Logging in (as far as it goes)

To log in, I need to make a request to my services with the data gathered from my “login” form. The request is a POST and the in sent to the server as JSON (“content-Type:application/json” in the head. When I get a response back from the server, XMLHttpRequest calls getJwtProcessResponse():

function getJwt() {
  showResults("working ....");

  // Assemble data to log in, should match schema of MakeTokenViewModel
  const userName = document.getElementById("txtUserName").value;
  const role = document.getElementById("txtRole").value;
  const id = document.getElementById("txtId").value;
  const fail = document.getElementById("chkFail").checked;
  const message = 
    `{"UserName":"${userName}","Role": "${role}","Id": ${id},"Fail":${fail}}`;

  // Make the request
  const xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = getJwtProcessResponse;
  xhttp.open("Post", `${BASE_URL}jwt/maketoken`, true);
  xhttp.setRequestHeader("content-Type", "application/json");
  xhttp.send(message);
}

When I get a response back and it’s ready: if the status is 200, login succeeded, and I store the JWT in Local Storage with writeJwt() (since I’m not sending anything other than the JWT, I don’t have to parse it out of this.responseText). Otherwise, alert the user of the failure.

// Get and process the request
function getJwtProcessResponse() {
  if (this.readyState == 4) {
    if (this.status == 200) {
      writeJwt(this.responseText);
      showResults("token written to localStorage");
    }
    else {
      alert(`${this.status}\n ${this.responseText}`);
        showResults("Failed!");
    }
  }
}

Making a call to the Service

Here I am going to make a simple GET request with the JWT in Local Storage (if available)

// Make a call to the end point specified by urlExtension
// (each endpoint has a different permission, for demo purpose)
function makeCall(urlExtension) {
  showResults("working ....");
  const jwt = readJwt();
  const xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = makeCallProcessResponse;
  xhttp.open("Get", `${BASE_URL}values${urlExtension}`, true);
  // We want to test with the user not logged in
  if (!!jwt) {
      xhttp.setRequestHeader("Authorization", ` Bearer  ${jwt}`);
  }
  xhttp.send();
}

When I get a response back and it’s ready: if the status is 200, I am authorized to and call showResults() to show what I got back. Otherwise the user is alerted about the failure

function makeCallProcessResponse() {
  if (this.readyState == 4) {
    if (this.status == 200) {
      showResults(this.responseText);
    }
    else {
      alert(`${this.status}\n ${this.responseText}`);
      showResults("Failed!");
    }
  }
}

Logging out

You really don’t log off JWT, they expire. To simulate logging out of a site, you make Local Storage forget:

function deleteJwt() {
  clearJwt();
}

Reading JWT “payload”

You can embed data in middle part of the JWT (the Payload) as unencrypted Base64 encoded JSON (Yes, I stole it from StackOverflow).

//see https://stackoverflow.com/a/38552302/3819
function parseJwt(token) {
  const base64Url = token.split('.')[1];
  const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
  return JSON.parse(window.atob(base64));
}

The localStorage functions

These are the functions that actually read and write the JWT to localStorage:

function writeJwt(jwt) {
  if (typeof Storage !== "undefined") {
    localStorage.setItem("jwt", jwt);
  } else {
    showResults("Sorry, your browser does not support Web Storage...")
  }
}

function readJwt() {
  if (typeof Storage !== "undefined") {
    return localStorage.getItem("jwt");
  } else {
    showResults("Sorry, your browser does not support Web Storage...");
  }
  return "";
}

function clearJwt() {
  if (typeof Storage !== "undefined") {
    localStorage.removeItem("jwt");
  } else {
    showResults("Sorry, your browser does not support Web Storage...");
  }
}

The Whole Page

And here is the whole page (JS, CSS and HTML all in one):

<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      margin: 25px;
    }

    label {
      width: 80px;
      display: inline-block;
      margin: 2px;
    }

    input {
      margin: 2px;
    }

    button {
      width: 150px;
      margin: 2px;
    }

    #result {
      width: 100%;
      height: 150px;
    }
    .grid-container {
      width: 100%;
      display: grid;
      grid-gap: 10px;
      grid-template-columns: 1fr 1fr 1fr;
    }

    .grid-container {
      display: inline-grid;
    }
  </style>
</head>
<body>
  <h2>JWT Client</h2>
  <div id="theGrid"class="grid-container">
    <div id="data"class="grid-item" >
      <h3>Data for JWT</h3>
      <p>This is the data used to create the JWT. The Server recognizes 2 roles: "admin" and "super".</p>
      <p>(We can simulate a log in failure by checking "Fail")</p>
      <label for="txtUserName">User Name </label><input type="text" id="txtUserName" value="johns" /><br />
      <label for="txtRole">Role</label><input type="text" id="txtRole" value="admin" /><br />
      <label for="txtId">Id</label><input type="number" id="txtId" value="42" /><br />
      <label for="chkFail">Fail</label><input type="checkbox" id="chkFail" value="false" /><br />
    </div>
    <div id="access" class="grid-item">
      <h3>Make JWT</h3>
      <p>Here we get the JWT from the "server", store and retrieve the JWT.</p>
      <p>The JWT is stored in Local Storage.</p>
      <button type="button" onclick="getJwt()">Get Token</button><br />
      <button type="button" onclick="showJwt()">Show Token</button><br />
      <button type="button" onclick="decode()">Decode</button><br />
      <button type="button" onclick="deleteJwt()">Clear Token</button><br />
    </div>
    <div id="use" class="grid-item">
      <h3>Use JWT</h3>
      <p>Here we use the JWT we stored in Local Storage and make calls to       
      various endpoints which have different permissions on the server</p>
      <p>The Server decodes the claims in the JWT and returns them as JSON object</p>
      <button type="button" onclick="makeCall('')">Call "/"</button><br />
      <button type="button" onclick="makeCall('/admin')">Call "/admin"</button><br />
      <button type="button" onclick="makeCall('/super')">Call "/super"</button><br />
      <button type="button" onclick="makeCall('/either')">Call "/either"</button><br />
      <button type="button" onclick="makeCall('/open')">Call "/open"</button><br />
    </div>
  </div>
  <div id="results">
    <label for="result">Results</label><br />
    <textarea id="result"></textarea>
  </div>
  <script>
    const BASE_URL = "/api/";
    function getJwt() {
      showResults("working ....");

      // Assemble data to log in, should match schema of MakeTokenViewModel
      const userName = document.getElementById("txtUserName").value;
      const role = document.getElementById("txtRole").value;
      const id = document.getElementById("txtId").value;
      const fail = document.getElementById("chkFail").checked;
      const message = `{"UserName":"${userName}","Role": "${role}","Id": ${id},"Fail":${fail}}`;

      // Make the request
      const xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = getJwtProcessResponse;
      xhttp.open("Post", `${BASE_URL}jwt/maketoken`, true);
      xhttp.setRequestHeader("content-Type", "application/json");
      xhttp.send(message);
    }

    // Get and process the request
    function getJwtProcessResponse() {
      if (this.readyState == 4) {
        if (this.status == 200) {
          writeJwt(this.responseText);
          showResults("token written to localStorage");
        }
        else {
          alert(`${this.status}\n ${this.responseText}`);
          showResults("Failed!");
        }
      }
    }

    // Make a call to the end point specified by urlExtension
    // (each endpoint has a different permission, for demo purpose)
    function makeCall(urlExtension) {
      showResults("working ....");
      const jwt = readJwt();
      const xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = makeCallProcessResponse;
      xhttp.open("Get", `${BASE_URL}values${urlExtension}`, true);
      // We want to test with the user not logged in
      if (!!jwt) {
        xhttp.setRequestHeader("Authorization", ` Bearer  ${jwt}`);
      }
      xhttp.send();
    }

    function makeCallProcessResponse() {
      if (this.readyState == 4) {
        if (this.status == 200) {
          showResults(this.responseText);
        }
        else {
          alert(`${this.status}\n ${this.responseText}`);
          showResults("Failed!");
        }
      }
    }

    function showJwt() {
      const jwt = readJwt();
      if (jwt === null) {
        showResults("no token to display");
        return;
      }
      showResults(jwt);
    }

    function deleteJwt() {
      clearJwt();
    }

    function writeJwt(jwt) {
      if (typeof Storage !== "undefined") {
        localStorage.setItem("jwt", jwt);
      } else {
        showResults("Sorry, your browser does not support Web Storage...")
      }
    }

    function readJwt() {
      if (typeof Storage !== "undefined") {
        return localStorage.getItem("jwt");
      } else {
        showResults("Sorry, your browser does not support Web Storage...");
      }
      return "";
    }

    function clearJwt() {
      if (typeof Storage !== "undefined") {
        localStorage.removeItem("jwt");
      } else {
        showResults("Sorry, your browser does not support Web Storage...");
      }
    }

    function decode() {
      const jwt = readJwt();
      if (jwt == null) {
        showResults("no token to decode");
        return;
      }
      const parsed = parseJwt(jwt);
      showResults(JSON.stringify(parsed, null, 2));
    }

    //see https://stackoverflow.com/a/38552302/3819
    function parseJwt(token) {
      const base64Url = token.split('.')[1];
      const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
      return JSON.parse(window.atob(base64));
    };

    function showResults(results) {
      document.getElementById("result").value = results;
    }
  </script>
</body>
</html>

Saturday, April 13, 2019

JWT on .NET Core 2.2 and Little Else

I wanted to see how to implement JSON Web Tokens (JWT) in C#/ASP.NET Core 2.2 without the chaos of anything else, like passwords, a database or anything else. I have a complete example project on my GitHub. If you clone my respository, you can skip downn to Discussion.

Solution

I created a project that I called "SimpleJwt4Core22" that was configured not to use SSL and use port 55477 (so the URL would be "http://localhost:55477")

  1. Add the following configuration to appsettings.json:

    "Jwt": {
      "Site": "http://jrcs3.com",
      "SigningKey": "Not a safe place to put a security key, eh?",
      "ExperyInMinutes": "600"
     },
    
  2. Ensure that IConfiguration is injected into Startup.cs, the constructor and private field should look like this:

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }
    
    public IConfiguration Configuration { get; }
    
    (depending on which template you used to create the project, this code may already be present.)
  3. Configure site to use JWT for its AuthenticationScheme in Startup’s ConfigureServices() method.

    // JWT Begin Insert
    services.AddAuthentication(option =>
    {
      option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
      option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
      option.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    }).AddJwtBearer(options =>
    {
      options.SaveToken = true;
      options.RequireHttpsMetadata = true;
      options.TokenValidationParameters = new TokenValidationParameters()
      {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidAudience = Configuration["Jwt:Site"],
        ValidIssuer = Configuration["Jwt:Site"],
        IssuerSigningKey = new SymmetricSecurityKey(
          Encoding.UTF8.GetBytes(Configuration["Jwt:SigningKey"]))
      };
    });
    // JWT End Insert
    
  4. Ensure that MVC is configured at the end of Startup’s ConfigureServices() method.

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    

    (depending on which template you used to create the project, this code may already be present.)

  5. Add the following line to Startup’s Configure() method (just below the IsDevelopment() block)

    // JWT Begin Insert
    app.UseAuthentication();
    // JWT End Insert
    
  6. Ensure that MVC is enabled in Startup’s Configure() method, you should see this line:

    app.UseMvc();
    
    (depending on which template you used to create the project, this code may already be present.)
  7. Create a Controller and a ViewModel. I called the Controller "JwtController" and put it in the Controllers directory (create it if you need to) and I called ViewModel "MakeTokenViewModel"

    So here’s the code for the /ViewModels/MakeTokenViewModel.cs:

    using System.ComponentModel.DataAnnotations;
    
    namespace SimpleJwt4Core22.ViewModels
    {
      public class MakeTokenViewModel
      {
        [Required]
        public int Id { get; set; }
        [Required]
        public string UserName { get; set; }
        [Required]
        public string Role { get; set; }
        // To simulate login or other failure:
        public bool Fail { get; set; }
      }
    }
    

    And /Controllers/JwtController.cs:


    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Configuration;
    using Microsoft.IdentityModel.Tokens;
    using SimpleJwt4Core22.ViewModels;
    using System;
    using System.IdentityModel.Tokens.Jwt;
    using System.Security.Claims;
    using System.Text;
    
    namespace SimpleJwt4Core22.Controllers
    {
      [Route("api/[controller]")]
      [ApiController]
      public class JwtController : ControllerBase
      {
        private readonly IConfiguration _configuration;
        public JwtController(IConfiguration configuration)
        {
          _configuration = configuration;
        }
    
        [Route("maketoken")]
        [HttpPost]
        public ActionResult Login([FromBody] MakeTokenViewModel model)
        {
          // Simulate login or other failure:
          if (model.Fail)
          {
            return BadRequest("JWT Creation Failure");
          }
    
          var claim = new[]
          {
            new Claim("name", model.UserName),
            new Claim("id", model.Id.ToString()),
            new Claim("role", model.Role)
          };
          var signingKey = new SymmetricSecurityKey(
            Encoding.UTF8.GetBytes(_configuration["Jwt:SigningKey"]));
          int experyInMinutes = Convert.ToInt32(_configuration["Jwt:ExperyInMinutes"]);
    
          var token = new JwtSecurityToken(
            issuer: _configuration["Jwt:Site"],
            audience: _configuration["Jwt:Site"],
            expires: DateTime.UtcNow.AddMinutes(experyInMinutes),
            signingCredentials: new SigningCredentials(
              signingKey, SecurityAlgorithms.HmacSha256),
            claims: claim
          );
          return Ok(new JwtSecurityTokenHandler().WriteToken(token));
        }
      }
    }
    

    At his point you should be able to POST to the endpoint http://localhost:55477/api/jwt/maketoken with Postman, Fiddler or the following the curl command:

    curl -X POST -H "Content-Type: application/json" \
      -d '{"UserName": "dvader","Role": "admin","Id": 42}' \
      http://localhost:55477/api/jwt/maketoken
    

    I like to give curl command because they are short and sweet. On Windows 10 you can run curl on Windows Subsystem for Linux or Git Bash or a number of other shells. I added the line continuation character ('\') for readability. (In a future post I will consume this endpoint in Javascript

  8. To use the JWT, we need some endpoint that uses it. I created /Controllers/ValuesController.cs, with endpoints that provides with different endpoints that require different roles (admin & super):


    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Newtonsoft.Json;
    using System.Collections.Generic;
    using System.Security.Claims;
    
    namespace SimpleJwt4Core22.Controllers
    {
      [Authorize]
      [Route("api/[controller]")]
      [ApiController]
      public class ValuesController : ControllerBase
      {
        private readonly JsonSerializerSettings _serializerSettings;
        public ValuesController()
        {
          _serializerSettings = new JsonSerializerSettings
          {
            Formatting = Formatting.Indented
          };
        }
        // GET api/values
        [HttpGet]
        public IActionResult Get()
        {
          return handleRequest();
        }
    
        // All of these endpoints do the same thing except for the 
        // authorized roles
        [Route("admin")]
        [Authorize(Roles = "admin")]
        [HttpGet]
        public IActionResult GetAdmin()
        {
          return handleRequest();
        }
    
        [Route("super")]
        [Authorize(Roles = "super")]
        [HttpGet]
        public IActionResult GetSuper()
        {
          return handleRequest();
        }
    
        [Route("either")]
        [Authorize(Roles = "super,admin")]
        [HttpGet]
        public IActionResult GetBoth()
        {
          return handleRequest();
        }
    
        [Route("open")]
        [AllowAnonymous]
        [HttpGet]
        public IActionResult GetOpen()
        {
          return handleRequest();
        }
    
        private IActionResult handleRequest()
        {
          // Read the claims that I wrote in JwtController:
          var claims = ((ClaimsIdentity)User.Identity).Claims;
          var id = getClaimByType(claims, "id");
          var name = getClaimByType(claims, "name");
          // In JwtController, I created a claim for "role" 
          // so I would expect this to have a value:
          var role = getClaimByType(claims, "role");
          // however, by magic, this one has the value:
          var msRole = getClaimByType(claims, 
              "http://schemas.microsoft.com/ws/2008/06/identity/claims/role");
          var response = new
          {
            id,
            name,
            role,
            msRole
          };
          // Send the claims back in the Response:
          var json = JsonConvert.SerializeObject(response, _serializerSettings);
          return new OkObjectResult(json);
        }
    
        public static string getClaimByType(IEnumerable<Claim> jwt, string typeKey)
        {
          foreach (var claim in jwt)
          {
            if (claim.Type == typeKey)
            {
              return claim.Value;
            }
          }
          return string.Empty;
        }
      }
    }
    

    Again we are ready to make a GET to the endpoint http://localhost:55477/api/values (or one if it's sub routes) with Postman, Fiddler or the following the curl command (this time we need to send the JWT:

    jwt=$( \
      curl -X POST -H  "Content-Type: application/json" \
        -d '{"UserName": "ckent","Role": "super","Id": 42,"fail":false }' \
        http://localhost:55477/api/jwt/maketoken \
    )
    curl -X GET -H "Authorization: Bearer $jwt" http://localhost:55477/api/values/super
    


Discussion

The code in Startup.cs configures and enables Authentication and sets it to the JwtBearer scheme. I put some configuration data in appsettings.json.

Yes, this is a rather stilted example. It does not validate a password and allows the user to "log in" with any role. I have one endpoint to obtain a JWT, and several others to simulate getting data with different required roles (and one that doesn’t even require you to be logged in at all).

Logging In/Getting your JWT

To make a JWT you need to create an IEnumerable of Claims that you wish to make:

var claim = new[]
{
    new Claim("name", model.UserName),
    new Claim("id", model.Id.ToString()),
    new Claim("role", model.Role)
};

Then you construct a new JwtSecurityToken with the claims, signing key, expery time, etc to make your JWT:

var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(
    _configuration["Jwt:SigningKey"]));
int experyInMinutes = Convert.ToInt32(_configuration["Jwt:ExperyInMinutes"]);
string site = _configuration["Jwt:Site"];

var token = new JwtSecurityToken(
    issuer: site,
    audience: site,
    expires: DateTime.UtcNow.AddMinutes(experyInMinutes),
    signingCredentials: new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256),
    claims: claim
);

Return the JWT. Refer to JwtController.Login() for the complete example.

Securing your endpoints

The endpoints in ValuesController are secured with attributes. I applied the AuthorizeAttribute to the class, so you must be logged in to hit any endpoint in the class, unless the AllowAnonymousAttribute has been applied to the endpoint's method. You can further restrict access to an endpoint by applying an AuthorizeAttribute Roles set.

Here are all the endpoints:

Endpoint (URL) Attribute Notes
/api/values Must be logged in (have a JWT) with ANY role
/api/values/admin [Authorize(Roles = "admin")] Must be logged with the role "admin"
/api/values/super [Authorize(Roles = "super")] Must be logged with the role "super"
/api/values/either [Authorize(Roles = "admin,super")] Must be logged with either role "admin" or "super"
/api/values/open [AllowAnonymous] DOES NOT need to be logged in (doesn't need JWT)


Monday, July 23, 2018

AngularJS vs Angular: index.html and boostrapping

This is part of a series that compares AngularJS (the old Angular) to Angular.

For the first comparison, I’m going to look at index.html and how the apps are set up or bootstrapped.

AngularJS

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html ng-app="mainModule">
<head>
  <title>TasksA1</title>
  <script src="https://code.angularjs.org/1.7.0/angular.min.js"></script>
  <script src="https://code.angularjs.org/1.7.0/angular-resource.min.js"></script>
  <script src="https://code.angularjs.org/1.7.0/angular-route.js"></script>
  <script src="app.js"></script>  
  <script src="app-routing.module.js"></script>
  <script src="services/todo.service.js"></script>
  <script src="pages/home/home.component.js"></script>
  <script src="pages/to-do-list/to-do-list.component.js"></script>
  <script src="pages/to-do-item/to-do-item.component.js"></script>
  <!-- Angular CLR project somehow adds Boostrap into the file -->
  <link rel="stylesheet" 
  href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" 
  integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" 
  crossorigin="anonymous">
  <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
  <h1>ToDos using AngularJS (1)</h1>
  <a href="#!/toDoList">ToDos</a>
  |
  <a href="#!/toDoAdd">New ToDo</a>
  <div ng-view></div>
</body>
</html>
index.html

On line 2, there is the ng-app directive, telling AngularJS to do its magic. Lines 5-13 there are script tags, first Angulars then mine. Then on line 26 we have a div with a ng-view directive, that's where all the magic happens.

Angluar

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>TasksA6Ts</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <h1>ToDos using Angular /w TypeScript</h1>
  <a href="/toDoList">ToDos</a>
  |
  <a href="/toDoAdd">New ToDo</a>
  <app-root></app-root>
</body>
</html>
index.html

The app-root tag replaces the div with the ng-view directive. There is no ng-app directive or script tags. When I did a view source. But how does it know which files to insert; I think it gets them from app.module.ts (the files are reduced to ES5 and dumped into a single file).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import { ReactiveFormsModule , FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { ToDoItemComponent } from './pages/to-do-item/to-do-item.component';
import { ToDoListComponent } from './pages/to-do-list/to-do-list.component';
import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { HomeComponent } from './pages/home/home.component';

@NgModule({
  declarations: [
    AppComponent,
    ToDoItemComponent,
    ToDoListComponent,
    HomeComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    ReactiveFormsModule,
    FormsModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
app.module.ts

These are the files in the actual project, but an Angular app needs to be built. I built the app with the command ng build and when I look at the build results and this is the generated index.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>TasksA6Ts</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <h1>ToDos using Angular /w TypeScript</h1>
  <a href="/toDoList">ToDos</a>
  |
  <a href="/toDoAdd">New ToDo</a>
  <app-root></app-root>
<script type="text/javascript" src="runtime.js"></script>
<script type="text/javascript" src="polyfills.js"></script>
<script type="text/javascript" src="styles.js"></script>
<script type="text/javascript" src="vendor.js"></script>
<script type="text/javascript" src="main.js"></script>
</body>
</html>
Generated index.html

All of the TypeScript files mentioned in app.module.ts are transpiled into ES5 into main.js

About the series AngularJS vs Angular


AngularJS vs Angular: The Introduction

As I try to maintain my status as a “Full Stack Developer” I have been looking at Angular and AngularJS. So, what gives? Angular is an open source web application platform that Google released in 2016 to replace AngularJS (then called Angular). AngularJS is Google’s original Angular, released in 2010. Angular and AngularJS are completely different.

In this experiment I wrote a simple list/detail site in both AngularJS (in JavaScript ES5) and Angular (in TypeScript). I created a simple REST endpoint with JSON-Server.

Methodology

AngularJS

I took a project I wrote a coupe of years ago and simplified it and then refactored it to match the files structure of the Angular app (foo.ts became foo.js).

Angular

I created the app, the components and services using the Angular CLI (version 6). I put all of the REST calls in a “services” to match the architecture I used in the AngularJS app; most of the samples I found online called the http methods directly from the components.

The App

The Task List is the “Hello World” of databinding, so I went with this. I dropped the “People” table so we only have 1 table: “Todos”. Both apps do the same thing using the same structure as far as I could push it.

About the series AngularJS vs Angular

Thursday, June 28, 2018

ACID Cheat Sheet

This on is for Database Transactions

  • Atomicity – The transaction is all or nothing. Succeeds or fails as a unit.
    If the bank adds $100 to my account, then the $100 must come from your account.
  • Consistency – Outside of the transaction, we can only see the begin or end state of the transaction.
    We will never see the half of the transaction where I get the $100 and you haven’t given up your $100. (too bad).
  • Isolation – The transaction is hidden from the outside world until it is committed.
    I imagine that during a transaction there are two universes. In the transaction’s universe, the values change as you work though the steps. In the other universe, the values remain as they were before.
  • Durability – Once the transaction is committed, it is on the record forever.
    If they decide that I shouldn’t have gotten the $100 from you after the transaction was committed, they can create a new transaction where they take the $100 away from me, but they can’t reverse the committed transaction. You can’t rewrite history.

Tuesday, May 29, 2018

4 Pillars of Object Oriented Programming Cheat Sheet

Another cheat sheet for interviewing.
I think of the 4 pillars consisting of 2 coins. Abstraction / Encapsulation and Inheritance / Polymorphism. So here they are:
  • Abstraction – Look at the thing we are modeling: What is it? What are its characteristics? What does it do? Make the object as simple as possible and don't include unnecessary functionality. Data Hiding for simplification.
  • Encapsulation – Create a black box around the how. You interact with an object through public properties (setters and getters) and methods. Data Hiding for security.
Both Abstraction and Encapsulation are about all about hiding stuff from us. Protecting us from unnecessary complexity. Abstraction takes place when we fill out our CRC cards when we are designing our classes and Encapsulation takes place when we actually write the code.

  • Inheritance – Reuse code! A child class inherits from a parent, from a grandparent, from great grandparent, and so on .. I think of examples of class hierarchies, like Animal, Dog, Pitbull, etc.
  • Polymorphism – From "many forms": A child can be substituted for the parent. If you cast a Pitbull as a Dog, you can call the Dog.Bark() method and the Pitbull.Bark() will be run (if it has been overridden). Also, you can have a collection of Dogs, and issue the Bark() command on each of them without caring which kind of Dog is barking (Pitbull or Corgi).
I think of Inheritance and Polymorphism as cause and effect. Because a Pitbull is derived from Dog (Inheritance), the Pitbull can bark like a Dog (Polymorphism).

Friday, May 25, 2018

S.O.L.I.D. Principals Cheat Sheet


I am between gigs, so I have been given opportunities to discus the SOLID Principals along with others of the classics of Object Orientation and basic Computer Science.

The SOLID Principals are somehow connected to Robert C. “Uncle Bob” Martin and his 2000 paper Design Principles and Design Patterns. The word “Solid” appears nowhere in the document. Well anyway, the SOLID Principals are:

  • Single Responsibility Principle – A class should do one thing and do it well. No more epic methods or “manager” classed that do everything.
  • Open/Closed Principle – Open for extension but closed for modification. When you publish an API, others are depending on you. Don’t change the way that a method works. Someone may even be depending on a bug in your code!
  • Liskov Substitution Principle – You should be able to substitute a child for a parent and everything work. Named after Barbra Liskov of MIT; learning this kind of detail makes it easier for me to remember.
  • Interface Segregation Principle – More smaller interfaces! Each interface should do 1 thing. Avoid creating a monster interface that does everything. (this is an extension of the Single Responsibility Principal, right?)
  • Dependency Inversion – Don’t create an object directly. Use an abstraction to create it. Whether it is the Abstract Factory pattern, an IOC container, simply pass in the object in, or whatever.