While sending HTTP requests to our server, we need to use the Angular HttpClient. Of course, we may handle all the HTTP requests from every component and process the response as well, but it is not a good practice. It is much better to make the repository for your requests and then send the request URI to that repository. The repository should take care of the rest.
For the complete navigation and all the basic instructions of the Angular series, check out: Introduction of the Angular series.
So, let’s start with the environment files first.
Working With Environment Files
While this project is in development mode the server’s endpoint address is the http://localhost:[Port Number]
. With the application in the production environment, the endpoint is different, something like www.accountowner.com
. So, we want Angular to take care of that. That said, in the development mode, it should send requests towards the development URI, and in the production environment to a different address.
Let’s implement that.
In Visual Studio Code’s explorer window, we are going to search for the environments folder: src/environments
. Inside that folder, we are going to find two files, the environment.prod.ts
, and the environment.ts
. We are going to use the first one for the production configuration and the second one for the development configuration.
So, let’s start with the environment.prod.ts
modification:
export const environment = { production: true, urlAddress: 'http://www.accountowner.com' };
Next, let’s modify the environment.ts
file:
export const environment = { production: false, urlAddress: 'http://localhost:5000' };
Now we are going to create a service, which we can use to get the valid environment urlAddress
.
Let’s create a new environment-url.service.ts
file:
ng g service shared/services/environment-url --skip-tests
This command will create a new shared/services folders, and inside the service file:
CREATE src/app/shared/services/environment-url.service.ts (143 bytes)
About the Angular Services
Services are just classes, which provide us with some business logic relevant to our components. These services must be injected into a component using constructor injection. Furthermore, our code becomes more maintainable and readable once we extract the logic from a component to service.
When we want to use a service, we need to inject it into a component’s constructor. Therefore, it is always decorated with the @Injectable
decorator.
We should use services whenever we have code that we can reuse in other components, or extract part of the code from our components.
That said, let’s continue our work with the environment files by modifying the environment-url.service.ts
file:
import { environment } from './../../../environments/environment'; import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class EnvironmentUrlService { urlAddress: string = environment.urlAddress; constructor() { } }
The urlAddress
property accepts the value of the urlAddress
defined in the environment file. Angular knows if it is a production or development environment and is going to supply us with a valid value of that urlAddress
. We can check that in the angular.json file
:
"configurations": { "production": { ... "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ],
We can see that Angular will replace files in production mode.
Creating Angular Repository File
Now we can configure the HttpClientModule and create the repository service.
First, we need to import the HttpClientModule inside the app.module.ts
file:
import { HttpClientModule } from '@angular/common/http';
Then let’s place it inside the imports
array:
imports: [ BrowserModule, AppRoutingModule, BrowserAnimationsModule, HttpClientModule, CollapseModule.forRoot() ]
After that, let’s create a service file and name it owner-repository.service.ts
. We are going to place it in the same folder in which the environment service resides. In this service, we are going to create GET, POST, PUT, and DELETE requests for the owner entity from our server API:
ng g service shared/services/owner-repository --skip-tests
After the file creation, we are going to create a new _interfaces
folder under the app
folder, and add a new owner.model.ts
file:
export interface Owner{ id: string; name: string; dateOfBirth: Date; address: string; }
Once we have our interface in place, we can modify the repository file:
import { Owner } from './../../_interfaces/owner.model'; import { EnvironmentUrlService } from './environment-url.service'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class OwnerRepositoryService { constructor(private http: HttpClient, private envUrl: EnvironmentUrlService) { } public getOwners = (route: string) => { return this.http.get<Owner[]>(this.createCompleteRoute(route, this.envUrl.urlAddress)); } public createOwner = (route: string, owner: Owner) => { return this.http.post<Owner>(this.createCompleteRoute(route, this.envUrl.urlAddress), owner, this.generateHeaders()); } public updateOwner = (route: string, owner: Owner) => { return this.http.put(this.createCompleteRoute(route, this.envUrl.urlAddress), owner, this.generateHeaders()); } public deleteOwner = (route: string) => { return this.http.delete(this.createCompleteRoute(route, this.envUrl.urlAddress)); } private createCompleteRoute = (route: string, envAddress: string) => { return `${envAddress}/${route}`; } private generateHeaders = () => { return { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) } } }
Repository Code Explanation
Let’s explain this code.
First, we inject the Angular HttpClient and the environment variable into the constructor. Then we create functions that are going to wrap up our requests. The getOwners
function is a wrapper for the GET request. It accepts the route parameter of the string type (api/owner) and then combines it with the environment variable (localhost or www…). After all of that, we are going to have the route like http://localhost:5000/api/owner
if it is a development environment, which perfectly fits our requirements on the server-side.
The second function, createOwner
, is a wrapper for a POST request. It also generates a route, but additionally receives a body (an entity which we are creating) and generates headers. For this example, we are just creating the Content-Type
inside header. But if we need additional values inside the header, we could just add another key-value pair inside the HttpHeaders
object.
The updateOwner
function is pretty much the same as the create
function, except, it sends the PUT request. Lastly, the deleteOwner
function is a wrapper for the DELETE request which accepts the route like (api/owner/id). Both of these functions are missing a strongly typed HTTP method (put and delete) because we don’t expect any object as a response from the server. If everything goes well, we are going to get a 204 as a response without a response body.
The Subscription on the HTTP Calls
These wrapper functions need a subscription in order to work. In this post, we are only creating a repository with the HTTP calls. But as soon as we start creating our pages, we are going to use the subscription.
For now, we are just going to show you one example of a subscription:
owners: Owner[]; constructor(private repo: OwnerRepositoryService) { } private consumeGetFromRepository = () => { this.repo.getOwners('api/owner') .subscribe(own => { this.owners = own; }) }
As you may notice, we are calling the getOwners
function from the repository, but that function won’t be executed until we call the subscribe
function. The result from the response is going to be stored in the own
parameter.
Conclusion
Excellent, now we have our repository prepared and we are ready to create components, which are going to use this repository functions to show results in a browser.
In the next part of the series, we are going to show you how to use lazy content loading in Angular. Additionally, we will show the result data on the page.