Connecting Angular to a REST API
Tags: angular, nx, fullstack, restapi
Published: 2023-03-30 15:08:40

 ![Full Stack Development Series Part 3: Connecting Angular to a REST API](https://thefullstack.engineer/content/images/2023/02/Full-Stack-Development-Series-Part-3--1-.png)

Welcome back! In part 3 of this series we're going to dive into what it takes to consume a REST API from an Angular-based front end. By the end of this post you will see:

- Creating a "feature" library for our first component
- Creating a "data-access" library for front-end HTTP code
- Updates to shared data structures for strongly-typed HTTP requests/responses in both applications
- Using the `async` pipe to create reactive templates and display data
- Basic CSS styling

Other posts in this series:

- [An Introduction](https://thefullstack.engineer/full-stack-development-series-an-introduction?utm_source=dev.to&utm_medium=blog&utm_term=fsds_ng_to_nest)
- Part 1: [Getting Started With Nx, Angular, and NestJS](https://thefullstack.engineer/full-stack-development-series-part-1-getting-started-with-nx-angular-and-nestjs?utm_source=dev.to&utm_medium=blog&utm_term=fsds_ng_to_nest)
- Part 2: [Creating a REST API](https://thefullstack.engineer/full-stack-development-series-part-2-creating-a-rest-api-with-nestjs?utm_source=dev.to&utm_medium=blog&utm_term=fsds_ng_to_nest) 
- Part 3: [Connecting Angular to a REST API](https://thefullstack.engineer/full-stack-development-series-part-3-connect-angular-with-nestjs-api?utm_source=dev.to&utm_medium=blog&utm_term=fsds_ng_to_nest) (this post)

If you want to skip ahead to the code, you can checkout out the repository: [wgd3/full-stack-todo@part-03](https://github.com/wgd3/full-stack-todo/tree/part-03?ref=the-full-stack-engineer)

> If you'd like access to these articles as soon as they're available, or would like to be notified when new content has been posted, please subscribe to my newsletter: [The Full Stack Engineer Newsletter](https://thefullstack.engineer/#/portal/signup?utm_source=dev.to&utm_medium=blog&utm_term=fsds_ng_to_nest)

## Fire It Up

As I mentioned in a previous post, my preferred way to get all apps up and running is with this command:

```shell
> nx run-many --target=serve --all
```

Once that's running, you can visit the `client` app by navigating to http://localhost:4200 in your browser. You'll be greeted by the placeholder page from Nx:

![Full Stack Development Series Part 3: Connecting Angular to a REST API](https://thefullstack.engineer/content/images/2023/02/localhost_4200_.png)

Nothing much to see here, other than some very helpful links if it's your first time using Nx. Let's clean up the Nx placeholders before moving forward. First step, you can delete `apps/client/src/app/nx-welcome.component.ts`. Following that, update the `app.*` files like so:

```typescript
import { RouterModule } from '@angular/router';
import { Component } from '@angular/core';

@Component({
  standalone: true,
  imports: [RouterModule],
  selector: 'fse-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  title = 'client';
}

```

_apps/client/src/app/app.component.ts_

```typescript
<router-outlet></router-outlet>

```

_apps/client/src/app/app.component.html_

Now we're ready to add our first component!

## The First Client Library

In order to display anything in our UI, there needs to be a "container" component in which to display information. Everything displayed on a page in an Angular app is a component, and that includes every descendent of the `<body>` element.

By using the library generator for this component, we accomplish a few things:

1. Modularity. An isolated library is easier to test and refactor as necessary.
2. Automatic component generation with a template and stylesheet, pre-exported by an `index.ts` file
3. Automated updates to `tsconfig.base.json` which allows us to import content from the library anywhere in the application.

```shell
> nx generate @nrwl/angular:library FeatureDashboard \
--style=scss \
--directory=client \
--importPath=@fst/client/feature-dashboard \
--routing \
--simpleName 
--skipModule \
--standalone \
--standaloneConfig \
--tags=type:feature,scope:client
```

Our new library has been prepped, and thanks to the `--routing` flag there is now. a `libs/client/feature-dashboard/src/lib/lib.routes.ts` with easily-imported routes! In order to wire up the dashboard with the main app, the `app.routes.ts` file needs to be updated like so:

```typescript
import { Route } from '@angular/router';
import { clientFeatureDashboardRoutes } from '@fst/client/feature-dashboard';

export const appRoutes: Route[] = [...clientFeatureDashboardRoutes];

```

_apps/client/src/app/app.routes.ts_

 And in our browser...

![Full Stack Development Series Part 3: Connecting Angular to a REST API](https://thefullstack.engineer/content/images/2023/02/Screen-Shot-2023-02-22-at-3.05.59-PM.png)

It's definitely not pretty, but it's a start!

## Data Access library for HTTP Communication

Angular has some [extensive documentation](https://angular.io/guide/http?ref=the-full-stack-engineer) on their HTTPClient library, so I won't dive too deep.

```typescript
import { bootstrapApplication } from '@angular/platform-browser';
import {
  provideRouter,
  withEnabledBlockingInitialNavigation,
} from '@angular/router';
import { provideHttpClient } from '@angular/common/http';

import { AppComponent } from './app/app.component';
import { appRoutes } from './app/app.routes';

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(appRoutes, withEnabledBlockingInitialNavigation()),
    provideHttpClient(),
  ],
}).catch((err) => console.error(err));

```

_apps/client/src/main.ts_

```shell
> nx generate @nrwl/angular:library DataAccess \
--style=scss \
--directory=client \
--importPath=@fst/client/data-access \
--simpleName \
--skipModule \
--standalone \
--standaloneConfig
```

_Generating the data-access library_

Delete all `data-access.component.*` files under `libs/client/data-access/src/lib/data-access` and update `index.ts` to remove exports.

```shell
> nx generate @schematics/angular:service Api \
--project=client-data-access \
--path=libs/client/data-access/src/lib
```

_Generating the API service_

Update `ApiService` with some base methods:

```typescript
import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class ApiService {
  private readonly http = inject(HttpClient);

  getAllToDoItems(): Observable<unknown[]> {
    return of([]);
  }

  getToDoById(todoId: string): Observable<unknown> {
    return of();
  }

  createToDo(todoData: unknown): Observable<unknown> {
    return of();
  }

  updateToDo(todoId: string, todoData: unknown): Observable<unknown> {
    return of();
  }

  createOrUpdateToDo(todoId: string, todoData: unknown): Observable<unknown> {
    return of();
  }

  deleteToDo(todoId: string): Observable<unknown> {
    return of();
  }
}

```

_libs/client/data-access/src/lib/api.service.ts_

### What's this about? `inject(HttpClient)`
<button><svg id="Regular" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M23.25,7.311,12.53,18.03a.749.749,0,0,1-1.06,0L.75,7.311"></path></svg></button>

Dependency Injection! Traditionally, a class's `constructor()` was used to "inject" dependencies into that class. This can quickly become messy when you have more than 1-2 dependencies, even more so when those dependencies need their own decorators such as `@Self()`. With Angular 15, [inject](https://angular.io/api/core/inject?ref=the-full-stack-engineer) can be used instead to place dependencies outside of a constructor.

Update return signatures to use `ITodo` interface:

```typescript
  getAllToDoItems(): Observable<ITodo[]> {
    return of([]);
  }
```

## Updating Shared Data Structures

In the last post, DTOs were introduced to enforce strictly-typed payloads for our API. These DTOs can not be used by Angular directly, however we can update the `ITodo` interface file with types that the DTOs can implement. We need types for creating, updating, and upserting to-do items:

```typescript
export interface ITodo {
  id: string;
  title: string;
  description: string;
  completed: boolean;
}

export type ICreateTodo = Pick<ITodo, 'title' | 'description'>;
export type IUpdateTodo = Partial<Omit<ITodo, 'id'>>;
export type IUpsertTodo = ITodo;
```

_libs/shared/domain/src/lib/models/todo.interface.ts_

Going back to the ServerFeatureTodo library, the DTOs can be updated to implement these new types:

```typescript
export class CreateTodoDto implements ICreateTodo {
  //
}

export class UpsertTodoDto implements IUpsertTodo {
  //
}

export class UpdateTodoDto implements IUpdateTodo {
  // 
}
```

_libs/server/feature-todo/src/lib/dtos/todo.dto.ts_

Our Angular app can now make REST calls and use these CRUD interfaces to ensure the call signature matches what our API requires! Let's update the ApiService to reflect the changes, and return real data:

```typescript
  getAllToDoItems(): Observable<ITodo[]> {
    return this.http.get<ITodo[]>(`/api/todos`);
  }

  getToDoById(todoId: string): Observable<ITodo> {
    return this.http.get<ITodo>(`/api/todos/${todoId}`);
  }

  createToDo(todoData: ICreateTodo): Observable<ITodo> {
    return this.http.post<ITodo>(`/api/todos`, todoData);
  }

  updateToDo(todoId: string, todoData: IUpdateTodo): Observable<ITodo> {
    return this.http.patch<ITodo>(`/api/todos/${todoId}`, todoData);
  }

  createOrUpdateToDo(todoId: string, todoData: IUpsertTodo): Observable<ITodo> {
    return this.http.put<ITodo>(`/api/todos/${todoId}`, todoData);
  }

  deleteToDo(todoId: string): Observable<never> {
    return this.http.delete<never>(`/api/todos/${todoId}`);
  }
```

_libs/client/data-access/src/lib/api.service.ts_

> 💡 At some point during the development of this post, I got tired of using the very long `/api/server-feature-todo` endpoint - not to mention, it doesn't exactly conform to REST conventions. As such, the controller decorator was updated to shorten the endpoint:  
`@Controller({ path: 'todos' })` which makes endpoints `/api/todos`


> 💡 We use relative URLs since our Angular application is configured to automatically proxy relative URLs to the back end. If a full URL scheme was specified the proxy would not be used.

## Displaying The Results

It's time to finally show the API responses in the UI!

<iframe src="https://tenor.com/embed/17368070" width="600" height="400" frameborder="0"></iframe>

First step is to connect our dashboard component to the ApiService:

```typescript
@Component({
  selector: 'full-stack-todo-feature-dashboard',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './feature-dashboard.component.html',
  styleUrls: ['./feature-dashboard.component.scss'],
})
export class FeatureDashboardComponent {
  private readonly apiService = inject(ApiService);

  todoItems$ = this.apiService.getAllToDoItems();
}

```

_libs/client/feature-dashboard/src/lib/feature-dashboard/feature-dashboard.component.ts_

> 💡 `todoItems$` doesn't hold any data yet! It needs a subscriber, which in this case will be an [AsyncPipe](https://angular.io/api/common/AsyncPipe?ref=the-full-stack-engineer) in the template. This pipe automatically handles subscribing/unsubscribing for us, so there's no additional code needed.

Double check that Angular's proxy config is properly defined:

```json
{
  "/api": {
    "target": "http://localhost:3333",
    "secure": false,
    "logLevel": "debug"
  }
}
```

_apps/client/proxy.conf.json_

> 💡 I stumbled across a small issue with my setup, where the `proxy.conf.json` file added a `/api` suffix to the `target` value. This was resulting in 404s on the UI, and I'll admit I was embarrassed I didn't understand why immediately.  
Bonus knowledge: As of Angular 13, [logLevel](https://github.com/angular/angular-cli/issues/22112?ref=the-full-stack-engineer#issuecomment-962987474) does not actually print to console while you run the dev server! To see that output you need to run the dev server with a `--verbose` flag.

And now display the results from our API call!

```html
<p>feature-dashboard works!</p>

<ul>
    <li *ngFor="let todo of todoItems$ | async; let i = index">{{i}}. {{ todo.title }}</li>
</ul>
```

_Yes, <ol> would automatically number our list items (and start from 1!) but for demonstration purposes I used <ul>_

![Full Stack Development Series Part 3: Connecting Angular to a REST API](https://thefullstack.engineer/content/images/2023/02/Screen-Shot-2023-02-22-at-4.16.59-PM.png)

## Making It Pretty... ish

I usually hold off on any styling until I've got a decent amount of code written, and I'll dive into styling an Angular app in another post, but for demonstration purposes I updated these to-do items with a little flare.

```html
<div class="todo-list">
  <div class="todo" *ngFor="let todo of todoItems$ | async; let i = index">
    <h2 class="todo__title">#{{ i + 1 }} {{ todo.title }}</h2>
    <p class="todo__description">{{ todo.description }}</p>
    <small class="todo__id">ID: {{ todo.id }}</small>
    <br />
    <small class="todo__completed-label"
      >Completed:
      <span class="todo__completed-value--{{ todo.completed }}">{{
        todo.completed
      }}</span></small
    >
  </div>
</div>
```

_libs/client/feature-dashboard/src/lib/feature-dashboard/feature-dashboard.component.html_

```scss
// container element for the (vertical) list
.todo-list {
  display: flex;
  flex-direction: column;
  
  // "owl" pattern used for spacing between list items
  > * + * {
    margin-block-start: 1em;
  }
}

// block-level class name
.todo {
  width: 30rem;
  padding: 8px;
  box-shadow: 4px 4px 8px 0px;
  border: 1px solid #000000;
  font-family: Arial, Helvetica, sans-serif;

  // element-level class name
  &__title {
    margin-block-start: 0;
  }

  // element-level class name
  &__id {
    color: #a5a5a5;
  }

  // element-level class name
  &__completed-value {
  
    // modifier-level class name
    &--false {
      color: red;
    }
    
    // modifier-level class name
    &--true {
      color: green;
    }
  }
}
```

_libs/client/feature-dashboard/src/lib/feature-dashboard/feature-dashboard.component.scss_

> 💡 What's with the CSS class naming scheme? [BEM 101](https://css-tricks.com/bem-101/?ref=the-full-stack-engineer)  
This application does not incorporate any styling frameworks (yet!) such as Tailwind, Bootstrap, Angular Material, etc. But even with a framework, you should decide on a naming convention for your CSS classes for consistency purposes. I've used BEM for a long time, and am of the opinion that it's easy to pick up for new developers. 

![Full Stack Development Series Part 3: Connecting Angular to a REST API](https://thefullstack.engineer/content/images/2023/02/Screen-Shot-2023-02-22-at-4.40.35-PM.png)

## Summary

At this point you technically have a "full-stack" application! Bare as it may be, there is a back-end API (with an ephemeral data store) and a front-end UI in one neat monorepo. Speaking of monorepos, I'd like to highlight one of Nx's cooler features now that we have a handful of libraries to work with. Nx offers the ability to create dependency graphs in a fancy UI with it's `nx dep-graph` command:

![Full Stack Development Series Part 3: Connecting Angular to a REST API](https://thefullstack.engineer/content/images/2023/02/graph.png)

We have successfully implemented a hierarchy of apps and libraries, being mindful of both a separation of concerns _and_ shared data!

I hope you found this post useful in getting started on the front-end side of a full-stack application. The next entry in this series will focus on forms, front-end validation, and UI interaction. There's still a lot of ground to cover, so stay tuned for the next post!

All code up to this point can be found here: [wgd3/full-stack-todo@part-03](https://github.com/wgd3/full-stack-todo/tree/part-03?ref=the-full-stack-engineer)