Full Stack Development Series Part 3: Connecting Angular to a REST API
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. This post will cover creating libraries, using strongly-typed HTTP interfaces, and the Angular async pipe.
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
- Part 1: Getting Started With Nx, Angular, and NestJS
- Part 2: Creating a REST API
- Part 3: Connecting Angular to a REST API (this post)
If you want to skip ahead to the code, you can checkout out the repository: wgd3/full-stack-todo@part-03
Fire It Up
As I mentioned in a previous post, my preferred way to get all apps up and running is with this command:
> 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:
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:
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:
- Modularity. An isolated library is easier to test and refactor as necessary.
- Automatic component generation with a template and stylesheet, pre-exported by an
index.ts
file - Automated updates to
tsconfig.base.json
which allows us to import content from the library anywhere in the application.
> 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:
And in our browser...
It's definitely not pretty, but it's a start!
Data Access library for HTTP Communication
Angular has some extensive documentation on their HTTPClient library, so I won't dive too deep.
Delete all data-access.component.*
files under libs/client/data-access/src/lib/data-access
and update index.ts
to remove exports.
Update ApiService
with some base methods:
What's this about? inject(HttpClient)
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 can be used instead to place dependencies outside of a constructor.
Update return signatures to use ITodo
interface:
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:
Going back to the ServerFeatureTodo library, the DTOs can be updated to implement these new types:
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:
/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
Displaying The Results
It's time to finally show the API responses in the UI!
First step is to connect our dashboard component to the ApiService:
todoItems$
doesn't hold any data yet! It needs a subscriber, which in this case will be an AsyncPipe 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:
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 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!
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.
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.
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:
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