Angular API hookup with Azure DevOps


Hey kids! Let's chat about how to use the subscribe function to connect your Angular UI to a backend API. It's quite simple, once you figure it out ... it only took me about 2 weeks to figure it out lol


We'll go over how to create your API first. If you have an API you have already created or you want to connect to, you can skip this step and scroll down to here!

Backend API Service


For the Backend, you want to create your new API in whatever language / IDE you work in. Once your basic structure is there, you'll want to create a new endpoint in your API.


The structure I personally use is: Controller to Interface to Service. That's what we'll use here, but you do you, boo <3


The way I build items, is I create the last thing first, then move up the chain. So we will start with building the service. We'll create a simple call to get a list of Projects in Azure DevOps using the Azure API (this will be the projects available, as in the image below).



Create a ProjectListService.cs file. You will need to use several packages that are out of the box for hooking up to Microsoft. These are the usings I will need for my specific solution, which may differ from yours f you're looking for different data.


using Microsoft.Extensions.Options;
using Microsoft.TeamFoundation.Core.WebApi;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.WebApi;

You will need a PAT (personal access token) connected to your or your organization's Azure accounts in order to have access to the API's in these usings. If you don't know what this is, please see the Microsoft documentation.


Next, let's create our method inside the service to get the list. We are going to use the async option to bring back a custom project model list object. If you aren't familiar with what async is, please see this reference guide. We also need a data model, so create your model where it makes sense to you.


  public class ProjectListModel
    {
        public string Id { get; set; }
        public string ProjectName { get; set; }

    }

public async Task<List<ProjectListModel>> GetProjectList(CancellationToken cancellationToken)
        {

We need to create our credential call to send our access token and receive the credentials back, and then create our connection.


The URL is the specific URL to your Azure private instance. It will generally look like this: https://[your company name].visualstudio.com/xx

VssCredentials creds = new VssBasicCredential(username, PAT);
using var connection = new VssConnection(new Uri(URL), creds);

Now, we take the new authorized connection to your private Azure instance, and request the data we want about our projects. Create the model you want for the data - here I'm only wanting the Project name and ID.


This could be refactored to simplify once you get your code working, I left it as is to make it easy to read for beginners.


var projectHttpClient = connection.GetClient<ProjectHttpClient>(cancellationToken);
            var ProjectList = await projectHttpClient.GetProjects();

            var projectList = new List<ProjectListModel>();
            foreach (var proj in ProjectList)
            {
                var project = new ProjectListModel();
                project.Id = proj.Id.ToString();
                project.ProjectName = proj.Name;
                projectList.Add(project);
            }

            projectList.Sort((x, y) => x.ProjectName.CompareTo(y.ProjectName));
            return projectList;

This will complete your service that calls the Microsoft API for the data.


Next, we move to creating the Interface to hide our service from the outside world (SOLID, people, SOLID). There are ways to automate this using software in Visual Studio, as well as other IDE's, but you can still write this out if you like to type :)


Create your interface and reference the service method.

public interface IProjectListService
{
  Task<List<ProjectListModel>> GetProjectList( CancellationToken cToken);
 }

Yes, that's it lol




But you do need to hook up your Interface to the service AND in the project ref itself if you're using Core or Ninject, or most other code spaces - We need to go back into our service and add it to be used by the service. So we update the service to:

public class ProjectListService : IProjectListService

This will allow you to inherit the interface.


Last step will be to open the Startup.cs file or the NinjectWebConfig file (or whatever you are using for your bindings) and add the appropriate line. This tells the program there is a relationship between the interface and service files.


Core: services.AddScoped<ITeamListService, TeamListService>();
Ninject:  kernel.Bind<ITeamListService>().To<TeamListService>();

Ok awesome, now we just need to build the public endpoint in the Controller.


Your controller endpoint should be PUBLIC. This is the entrypoint for you connection. If this is not public, the Presentation service we will build next, cannot connect to it. Let's name our Controller 'ProjectList'


 public ProjectListController()

Presentation Layer Service



gif

Sorry, it's not :)



The presentation layer is the 'middle man' to connect your Angular UI to the Backend we just built.


It will look, if not be exactly, like the backend we built above. In your Angular solution, you should have the Angular UI project. This presentation layer is only needed if your API and Angular front end UI are NOT in the same solution.


In looking at the below screenshot, the UI (Test_angular_with_datatable) project and the Presentation layer (Test_angular_presentation_layer) are in a solution together. The backend API we built above would be in a separate solution.


If your backend API is in the same solution with the UI, you do not need a presentation layer.


To create the presentation layer endpoint, you will create the new controller in a your presentation project.

public class ProjectsController : ControllerBase
    {

Create the new endpoint that will be connecting to the Backend API. This connection will be based off the tech and tools you are using. We used NSwag to generate the service client for us to tap into. So, we just call the service client from our self published Nuget package and it auto connects to the backend endpoint. You may need to do a manual API call.


The call inside the controller looks like this:

private readonly IServiceClient _serviceClient;
public ProjectsController(ServiceClient serviceClient)
{
_serviceClient = serviceClient ?? throw new ArgumentNullException(nameof(serviceClient));
}

public ActionResult<List<ProjectListModel>> GetProjects( CancellationToken cancellationToken = default)
        {
            try
            {
                return Ok(_serviceClient.ProjectListAsync(cancellationToken: cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult());
            }
            catch ()
            {
            }
}


Angular front end


Finally, we're ready to hook up the front end!





Let's say we want to inject the list of Projects into a dropdown box on our Angular UI. In the .ts file you're working in, you'll want to add a function to get the list. We need to subscribe to the data feed from our Presentation layer controller. First, we need to import our Presentation Service so we can use it. We used NSwag, so the files were auto created for us. If you are not using NSwag, check here for steps on connecting to a service.


We create the base service and imported the HttpClient into our project by creating the file api.service.provider.ts in the services folder.


import { HttpClient } from '@angular/common/http';
import { environment } from '../../environments/environment';
import {  PresentationServiceClient } from '../services/presentation-service.g';

const presentationClientFactory = (httpClient: HttpClient) => {
  return new PresServiceClient(httpClient, environment.presentation_BaseUrl);
};

export const presentationClientProvider = {
  provide: PresServiceClient,
  useFactory: presentationClientFactory,
  deps: [HttpClient]
};

We also imported the presentation-service.g.ts file from NSwag that is auto generated. This file can be added to the services folder we put the api.service.provider.ts file in.





Next, in your component.ts file where you want to display the data, add this import:

import { PresServiceClient} from '../services/presentation-service.g';
import { tap } from 'rxjs/operators';
import { Subject } from 'rxjs';

This will allow you to use the service, as well as properly subscribe to the data service.


Then add to your constructor and high level list object:


 constructor(private presentationServiceClient: PresServiceClient) { }
 
  project_names: Array<ListValues> = [];

Add the subscribe function by using the 'getProjects' method in the presentationLayerService object.


   getProjectList(): void { this.presentationServiceClient.getProjects(
    ).pipe(
      tap()
    ).subscribe(data => {
      if (data !== undefined && data.length > 0) {
        data.forEach((item: any) => {
          this.project_names.push({ value: item.projectName, viewValue: item.projectName })
        })
      }
      this.dtTrigger.next();
    });
  }

Make sure you call the function on initialization of the page so your dropsdown is filled when the page is visited. Don't forget to do your unsubscribe on destroy or you could end up with a severe memory leak.



ngOnInit(): void {
    this.getProjectList();
  }
  ngOnDestroy(): void {
    this.dtTrigger.unsubscribe();
  }

Now let's build out the view using our data above. We want to show the list in a dropdown object on the page. We use bootstrap basic select object for this. Remember, we are automatically filling the list 'project_names' in the getProjectList() function on initialization.



<label for="project_name">Azure Project Name * </label>
<select class="form-select" id="project_name"
       required
       formControlName="project_name">
       <option *ngFor="let proj_name of project_names"                      
          [ngValue]="proj_name.value">{{proj_name.viewValue}}</option>
 </select>
          


And there you have it!! The list of projects in your UI after a whole lot of connecting!! I hope this helps you to understand the different connections and how they relate. Drop me a line or comment if I missed any steps you're struggling with, I'm always happy to try and help!


Cheers!



gif




6 views0 comments