Building A Full Stack Web Application – Part 5: The API

This post is a continuation in a series about building a full stack web application.  Previous posts in the series:

Enough about data and the framework, let’s take a look at the Stocks Tracker API, and see how information from previous posts have gotten us to this point.

The Stocks Tracker API needs to provide data to a variety of consumers, in a REST-ful way, accessible via the HTTP protocol.  Additionally, the API needs to be testable from HTTP tools such as Fiddler, cURL and Postman.

 

Goals

I had some goals to accomplish with the API project in Visual Studio.  First, include only packages and code necessary to get the API running.  That meant not including any assemblies from the MVC framework, which Visual Studio ASP.NET project templates include by default for documentation purposes, but cause project bloat, and deployment of “dead code.”  Besides, a tool like Swagger provides a simple and lightweight way to document your API, without turning it into a web site.

Another goal was to leverage the relationships ASP.NET Identity has with Entity Framework and OWIN/Katana to provide authentication & authorization functionality for the API.  The API needs to grant resource access only to those users properly authenticated and authorized by Identity.

Finally, I wanted to leverage existing financial APIs that provide quotes and news items for stocks and other securities.

 

Startup & Configuration

I started by adding a new class library project to the Stocks Tracker solution, named StocksTracker.API (lest there be any confusion as to what this project provides), followed by Global.asax and OWIN Startup classes from the project-level context menu.  These classes allow us hooks into an application’s startup process, so that we can configure the application appropriately.

In Global.asax, the mighty Autofac is configured to register dependencies in its DI container.  Autofac has a nice extension method that allows registration of all IHttpController implementations in a single line of code.  This is also where we configure the database connection from values in the Web.config file (these values are overridden during the deployment phase).  To keep things tidy, I also register any classes that the authorization middleware will need to communicate with the application.


// create IoC container
var builder = new ContainerBuilder();
// register all API controllers
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

// register stock tracker context as singleton
builder.Register(pcf => new StocksTrackerContextFactory(sqlConnectionBuilder, false))
 .As<IObjectFactory<StocksTrackerContext>>()
 .SingleInstance();

// register objects used in user authentication/authorization
builder.Register(provider => new ApplicationOAuthProvider(
 ConfigurationManager.AppSettings["Identity.PublicClientId"],
 _container.Resolve<IUserAdministration>()))
 .As<IOAuthAuthorizationServerProvider>()
 .SingleInstance();

// register object that communicates between application and middleware authorization server
builder.Register(options => new OAuthAuthorizationServerOptions
{
 TokenEndpointPath = new PathString(ConfigurationManager.AppSettings["Identity.TokenEndpointPath"]),
 AuthorizeEndpointPath = new PathString(ConfigurationManager.AppSettings["Identity.AuthorizeEndpointPath"]),
 AccessTokenExpireTimeSpan = TimeSpan.FromDays(days),
 AllowInsecureHttp = true,
 Provider = _container.Resolve<IOAuthAuthorizationServerProvider>()
})
 .As<OAuthAuthorizationServerOptions>()
 .SingleInstance();

ASP.NET allows global configuration via the GlobalConfiguration static class.  Here is where we set Autofac as the default dependency resolver, and register any routes the API will expose (routing in Web API and MVC is an art unto itself. I prefer to use class- and method-level attributes to define application routes, instead of using the template collection, which is fragile and not intuitive).

Set Dependency Resolver:


// build container, and set dependency resolver
_container = builder.Build();
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(_container);

Define Routes:


// build container, and set dependency resolver
GlobalConfiguration.Configure(WebApiConfig.Register); // in Global.asax.cs
 config.MapHttpAttributeRoutes(); // in WebApiConfig.Register

Startup.cs is where ASP.NET recommends adding middleware to an application, and Stocks Tracker is no different.  OWIN passes an IAppBuilder object to the Startup class, and it’s here that the OWIN “pipeline” is constructed by adding modules to the builder.  Each module is constructed in such a way that it either processes the incoming HTTP request, or passes control to the next module until one or none have processed the request.  Besides OWIN middleware, there are many third-party modules available via NuGet, plus it’s easy to write your own custom middleware.


public void ConfigureAuth(IAppBuilder app)
{
  // Enable the application to use a cookie to store information for the signed in user...
  app.UseCookieAuthentication(new CookieAuthenticationOptions());
  
  // ...and to use a cookie to temporarily store information about a user logging in with a third party provider
  app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
  
  // Enable the application to use bearer tokens to authenticate users
  app.UseOAuthBearerTokens(OAuthOptions);
}

 

Authentication/Authorization

As seen above, the API is now configured with OWIN middleware that will a) allow authentication of a registered user, storing the user’s credentials in a browser cookie; b) allow authentication of an external user, storing external access information in a browser cookie; and, c) require OAuth bearer tokens for access to restricted resources.

OAuth allows users access to our resources, provided they are authenticated by a third party such as Google, Twitter, Microsoft or Facebook.  OWIN middleware decouples all of this from the application, reducing the process to a client/server interaction, with our API acting as the client, and OWIN in the server role.  OWIN provides a wide range of configuration options, which are then passed to the middleware.

Here is a simple OWIN configuration example from the Stocks Tracker API: Create an instance of OAuthAuthorizationServerOptions to populate the OWIN OAuth middleware server with some default values.  Include a custom provider derived from OAuthAuthorizationServerProvider to listen for and act on messages from the server.  The server options instance is passed to the middleware by the UseOAuthBearerTokens() method during startup.

Pretty complicated stuff, but worth a deep dive, especially since OAuth is the standard for third party website authorization.

 

Services
In the last post we explored the Framework project of interfaces and POCOs, and the API is where they get put to work.  Basically, each service is an implementation of a Framework interface, and each is registered with Autofac in the configuration phase for dependency injection.  The methods do little more than query Entity Framework for data, given the criteria passed to the method, and return collections of POCO objects for the API to serialize for its callers.


public class StockTrackersService : IStockTrackers
{
  // constructor with dependencies injected
  public StockTrackersService()
  
  public async Task<StockTrackerRecord> GetStockTrackerAsync(int stockTrackerId)
  {
    using (var ctx = _stocksTrackerContextFactory.GetObject())
    {
      // take advantage of async/await
      return await ctx.StockTrackers
      .SingleOrDefaultAsync(tracker => tracker.StockTrackerId == stockTrackerId);
    }
  }
}

The UserAdministration service, however, is declared entirely within the API project, so as not to add an unnecessary Identity dependency to Framework.  Most examples and project templates instantiate Identity’s UserManager, UserStore, RoleManager and RoleStore classes all over the place, so UserAdministration is a nice facade to isolate and expose Identity functionality through a common interface.

Of note are three services that rely on third party APIs for quote, headline and chart data.  These services provide wrappers around the third party APIs, so that the resources are consumed in a manner consistent with the EF services.  They are all public APIs from Yahoo! Finance:

Quotes

Headlines:

Charts:

Cool.

 

Controllers

By convention, an ASP.NET Web API controller defines methods that correspond to an HTTP request by returning an appropriate IHttpActionResult implementation.  The Stocks Tracker API will do the same, with a controller for each service, providing methods for each HTTP verb (GET, POST, PUT, DELETE, etc.) necessary.

The Stocks Tracker controllers will take advantage of the wide range of helper methods and properties provided by the abstract ApiController base class, which include helpers for data validation, IHttpActionResults and users.  Each method will take advantage of .NET’s async/await functionality, which will help keep the API responsive.

These controllers are really the culmination of all the work up to this point: The routing engine routes an authenticated HTTP request to the appropriate API controller, which responds by returning data retrieved from a service call, or an appropriate error response.  StockTrackersController is a good example, as it has an action method for each of the major HTTP verbs, has its routing and authorization controlled declaratively, and has its dependencies injected by the global dependency resolver.


[Authorize] <- attribute enforces only authorized access to this controller's resources
[RoutePrefix("api/StockTrackers")] <- attribute defines the base route for this controller's actions
public class StockTrackersController : ApiController
{
  // this controller's service dependency
  private readonly IStockTrackers _stockTrackers;
  // constructor injection
  public StockTrackersController(IStockTrackers stockTrackers)
  {
     _stockTrackers = stockTrackers;
  }

  // GET api/StocksTrackers <- the route for this GET action
  [HttpGet] <- attribute enforces HTTP GET requests only
  [Route] <- attribute defines this route as the base route
  public async Task<IHttpActionResult> Get()
  {
    // ask the service for the user's stock trackers
    var stockTrackers = await _stockTrackers.GetStockTrackersForUser(User.Identity.GetUserId());
    // return an Ok action result (HTTP response 200) with data
    return Ok(stockTrackers.Select(MapStockTrackerRecordToObject));
  }

  // GET api/StockTrackers/1 <- the route for this GET action
  [HttpGet]
  [Route("{id:int}", Name = GetStockTrackerRouteName)] <- attribute defines base route plus mandatory parameter type
  public async Task<IHttpActionResult> Get(int id)
  {
    // return BadRequest action result (HTTP response 400)
    if (id == 0)
      return BadRequest();

    // return Ok action result with data
    // or NotFound (HTTP response 404)
  }

  // POST api/StockTrackers/Create <- the route for this POST action
  [Route("Create")] <- attribute defines base route plus "Create"
  [HttpPost] <- attribute enforces HTTP POST requests only
  public async Task<IHttpActionResult> Create(StockTrackerModel model)
  {
    // return BadRequest action result if model fails validation
    if (!ModelState.IsValid)
      return BadRequest(ModelState);

    // return Created action (HTTP response 201) with new data
    var newStockTracker = await _stockTrackers.AddStockTrackerForUserAsync(model0;
    return Created(newStockTracker);
  }

  // DELETE api/StockTrackers/1 <- the route for this DELETE action
  [Route("{id:int}")] <- attribute defines base route plus mandatory parameter type
  [HttpDelete] <- attribute enforces HTTP DELETE requests only
  public async Task<IHttpActionResult> Delete(int id)
  {
    // delete and return empty Ok action result
    await _stockTrackers.RemoveStockTrackerAsync(id);
    return Ok();
  }

  // PUT api/StockTrackers/1 <- the route for this PUT or PATCH action
  [HttpPatch] <- attribute enforces PATCH requests
  [HttpPut] <- attribute enforces PUT requests
  [Route("{id:int}")] <- attribute defines base route plus mandatory parameter type
  public async Task<IHttpActionResult> Put(int id, UpdateStockTrackerModel model)
  {
    // update and return Ok result with data
    var stockTracker = await _stockTrackers.UpdateStockTrackerAsync(model);
    return Ok(stockTracker);
  }
}

 

It’s worth noting the roles Identity and OWIN play behind the scenes with API controllers.  Any route that is decorated with an Authorize attribute requires
authentication and authorization of the request.  This is done is by looking for an access token in the HTTP Authorization header (OWIN), and attempting to match the token to a user (Identity via Entity Framework).  An authentication or authorization failure will result in a 401 Unauthorized response code returned to the caller.  Decorating a method with an AllowAnonymous attribute allows unauthorized access to the resource, provided the route is a match.

 

Testing

Sure, I had a nice API now, but how was I going to test it without a UI?  Thanks to www.asp.net (a HUGE influence on this project, and an invaluable resource) and Pluralsight (ditto) I checked out Fiddler, which allowed me to send test HTTP requests to my API.  Using examples from these resources I was able to register a user with the API, request an access token, then use the token to request access to restricted resources.  And just like that, my li’l API was returning me data!  Hot dog.

 

Summary

So now I have a working API able to perform CRUD actions in a REST-ful manner via HTTP.  In theory this API should be able to provide data to any number or clients including the web/mobile web (ASP.NET MVC, ASP.NET Web Forms, AngularJS, Aurelia, KnockoutJS, ES2015), hybrid apps (HTML/JavaScript/CSS in a view, wrapped by native APIs), or purely native apps for Anroid iOS or UWP.

Oh, and one other thing: Converting all this to ASP.NET Core will be almost a total rewrite.  Oh, well.

 

Up next: a UI!

Building A Full Stack Web Application – Part 3: Data Context

This post is a continuation in a series about building a full stack web application.  Previous posts in the series:

Microsoft’s Entity Framework (EF) is built around the concept of a data context, which is essentially a bridge between a database and classes, allowing us to interact with data as objects.  The EF class DbConext allows us to query and persist data in an object-oriented way, without having to deal with yucky SQL statements, database connection strings or transactions.

Context 

Back to Stocks Tracker.  Now that the data was modeled I added another class library project – Data.Context – which would be responsible for generating the database tables, keys and indexes, as well as seeding the database with any reference data.  This project provides a custom abstraction of DbContext, available to other layers.

But wait.  Remember how in a previous post, I showed how Microsoft’s Identity framework can be used to generate security classes that work hand-in-hand with Identity?  Well Identity also provides its own implementation of DbContext, IdentityDbContext, which allows us to interact with security data as objects.  Since I want to be able to query security objects via EF, the Stocks Tracker context will actually be derived from IdentityDbContext.

Let’s look a little closer at the context Stocks Tracker exposes to its callers.


/// <summary>
/// Class provides access to Entity Framework CRUD actions within the Stocks Tracker domain.
/// </summary>
public class StocksTrackerContext : IdentityDbContext<ApplicationUser>, IStocksTrackerContext

As you can see, StocksTrackerContext implements IdentityDbContext, which will use the ApplicationUser class defined in the Data.Models project. StocksTrackerContext also implements an interface, so that callers are limited to the data I want them to see.

public StocksTrackerContext()
: base("name=StocksTrackerContext")
{
}

public StocksTrackerContext(string connectionString, bool eagerOpen)
: base(connectionString)
{
_eagerOpen = eagerOpen;
if (eagerOpen)
Database.Connection.Open();
}

The constructors for DbContext are interesting.  Passing “name=StocksTrackerContext” forces EF to search the project for a connectionStrings node in a configuration file, and attempts to use the connection string matching the name to connect to the database.  The context can throw errors when called from a different project without a configuration file, so rather than duplicate config values all over the place, I prefer the second constructor, where an explicit connection string can be provided.


public IDbSet<Stock> Stocks
{
get { return _stocks ?? (_stocks = Set<Stock>()); }
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new StockConfiguration());
modelBuilder.Configurations.Add(new StockTrackerConfiguration());
modelBuilder.Configurations.Add(new StockTrackerStockConfiguration());
base.OnModelCreating(modelBuilder);
}

EF provides its own implementation of IEnumerable in the generic IDbSet interface.  This provides LINQ functionality on the collection, but with the ability to add and remove objects from the underlying collection.

But first we need a database.  EF provides a ton of configuration options for dealing with data, but I like to keep it simple.  Basically it boils down to configuring your entities, and migrating your data.  For configuration, EF provides a generic base class EntityTypeConfiguration, which for a model allows you to set constraints on tables (keys, name) and columns (size, nullability).

Configuration

/// <summary>
/// Defines the entity type configuration for the <see cref="Stock"/> domain model.
/// </summary>
public class StockConfiguration : EntityTypeConfiguration<Stock>
{
/// <summary&amp;gt;
/// Instantiates the StockConfiguration class.
/// </summary&amp;gt;
public StockConfiguration()
{
HasKey(s => s.StockId);

Property(s => s.TickerSymbol)
.IsRequired()
.HasMaxLength(10);

Property(s => s.OpenPrice)
.IsOptional()
.HasPrecision(8, 2);

HasMany(s => s.StockTrackerStocks)
.WithRequired(sts => sts.Stock)
.HasForeignKey(fk => fk.StockId);

ToTable("Stock");
}
}

With this in place EF has what it needs to translate a configuration class into DDL statements used to create or update a database schema.  Plus, EF tracks schema changes for you, and will automatically drop or add columns as the configuration class evolves.

Migration

For migrating data, EF provides an extensible base class DbMigrationsConfiguration, which requires a generic class of type DbContext.  This is where you would pass your custom implementation of DbContext, for this example StocksTrackerContext.

DbMigrationsConfiguration provides a single overridable method called Seed, passing the concrete implementation of DbContext.  From there any statements needed to “seed” the database with reference data or default users can be executed via the context.


/// <summary>
/// Class for migrating data to the Stocks Tracker domain.
/// </summary>
public class StocksTrackerMigrationsConfiguration: DbMigrationsConfiguration<StocksTrackerContext>

protected override void Seed(StocksTrackerContext context)
{
   // query, add, edit or delete data as needed
}

Initialization

With the context, configuration and migration classes in place, all that’s missing is a process that ties them all together.  Luckily, EF provides a number of options for initializing the database.  For Stocks Tracker I used the MigrateDatabaseToLatestVersion initializer, which is able to detect configuration changes and update the database schema accordingly (the Seed method will also be called during this process).


Database.SetInitializer(
 new MigrateDatabaseToLatestVersion<StocksTrackerContext, StocksTrackerMigrationsConfiguration>());

What’s nice about this is that the initialization can be called from within some bootstrapping code, or compiled into an executable called during an installation or some other process. I made a simple console project that initializes the database, then writes data to the console, so I know when there’s an error with the configuration or migration. The options EF provide make it easy to configure the database and context to work in development, testing or production environments.

Summing Up

As I mentioned, EF provides many options for creating a context that allows your application to connect to a data store, including the exact opposite of what the Stocks Tracker does (starting with a created and populated database, then generating configuration and context classes).

One cool option is Simon Hughes’ Reverse POCO Generator, which given an existing database will reverse engineer and generate POCO, configuration and context classes from tables and views, and will even generate classes for using stored procedures.  A familiarity with T4 templates is a big help, as most generators leverage T4s to some extent.

That was a lot to cover, but it’s enough for what I want Stocks Tracker to accomplish.  Next, we’ll look at the business layer.

Building A Full Stack Web Application – Part 2: Modeling the Data

This post is a continuation in a series about building a full stack web application.  Previous posts in the series:

There were a couple of goals I wanted to accomplish with the Stocks Tracker data.  The first goal was to keep any data access or modeling classes isolated in their own projects, accessible only through abstractions, so that any layer(s) reliant on data would have no knowledge of how the underlying data store worked.  The second goal was to leverage Microsoft’s Entity Framework (EF) and Identity frameworks.

Models

For data modeling, I added a new class library project to the Stocks Tracker solution, and called it Data.Models.  The data model was pretty simple, and only required adding a few NuGet packages, so that EF and Identity could work together:


<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="EntityFramework" version="6.1.0" targetFramework="net45" />
<package id="Microsoft.AspNet.Identity.Core" version="2.0.1" targetFramework="net45" />
<package id="Microsoft.AspNet.Identity.EntityFramework" version="2.0.1" targetFramework="net45" />
</packages>

The classes were simple POCOs that EF needs to define and map entity relationships to an underlying data store.  Pretty standard stuff, if you prefer EF’s code-first approach to generating database schemas.  However, throw in Identity and EF will also generate objects used by the Identity framework for security, such as tables to store user accounts, as well as support for third-party logins, such as Google, right out of the box.  Which is pretty cool, and necessary for a modern Web application.

The only thing needed was to create a class derived from IdentityUser, and EF is smart enough to create a security schema containing all the IdentityUser properties, as well as any custom properties defined in the derived class.  Mine adds the properties FirstName and LastName, which will be added as columns to the table AspNetUsers.


/// <summary>
/// Encapsulates the properties of an application user object.
/// </summary>
public class ApplicationUser : IdentityUser
{
/// <summary>
/// Instantiates the ApplicationUser class.
/// </summary>
public ApplicationUser()
{
}

/// <summary>
/// Gets and sets the first name value.
/// </summary>
public string FirstName { get; set; }

/// <summary>
/// Gets and sets the last name value.
/// </summary>
public string LastName { get; set; }
}

And that’s it for data modeling.  Up next, the data context.