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 URL to that repository. The repository should take care of the rest.
How do we achieve this?
That’s the topic of this blog post.
If you want to see all the basic instructions and complete navigation for the .NET Core series, check out the following link: Introduction of the .NET Core series.
For the complete navigation and all the basic instructions of the Angular series, check out: Introduction of the Angular series.
The source code is available at GitHub .NET Core, Angular, and MySQL. Part 9 – Source Code
This post is divided into several sections:
- About HttpClientModule and Angular HttpClient
- Working With Environment Files
- Creating Angular Repository File
- Repository Code Explanation
- The Subscription on the HTTP calls
- Conclusion
About HttpClientModule and Angular HttpClient
The thing that matters is that nowadays we use the HttpClientModule introduced in Angular 4.3 and not the old HttpModule. The new module gives us some advantages with processing responses and handling errors as well. With the old HttpModule, we would have to map our response and convert it to the JSON. Consequently, we would have to use the RxJS library because this library enables usage of the map function. With the new HttpClientModule and Angular HttpClient, the JSON response is set by default. Thus our project requires no result conversion at all.
The one way to check out our angular version is to start the application and to open developer tools. We will see the version in
<app-root> tag:
Working With Environment Files
While this project is in development mode the server’s endpoint address is the
http://localhost:5000. With the application in the production environment, the endpoint is different, something like
www.accountowner.com. What we want is that Angular takes care of that. So in the development mode, it should send requests towards localhost:5000, and in the production environment to some other address.
Let’s implement that.
In the side-bar of the visual studio code, search for the environments folder. Inside that folder, you are going to find two files, the environment.prod.ts
, and the environment.ts
. We are going to use the first one for configuring the production and the second one for configuring the development environment.
It is time for us to modify these files.
environment.prod.ts:
export const environment = { production: true, urlAddress: 'http://www.accountowner.com' };
environment.ts:
export const environment = { production: false, urlAddress: 'http://localhost:5000' };
Now we are going to create the service which will provide us with the valid environment
urlAddress.
Let’s create a new environment-url.service.ts
file with the ng g service shared/services/environment-url --skipTests
command:
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.
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. Use services whenever you have some code that you can reuse in other components, or extract part of the code from your components:
@Injectable({ providedIn: 'root', })
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 { public 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
. You can check that in the angular.json file:"configurations": { "production": { "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ],
You can see that Angular will replace files in the production mode.
Creating Angular Repository File
Let’s 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 imports array:
imports: [ BrowserModule, HttpClientModule, RouterModule.forRoot([ { path: 'home', component: HomeComponent }, { path: '404', component : NotFoundComponent}, { path: '', redirectTo: '/home', pathMatch: 'full' }, { path: '**', redirectTo: '/404', pathMatch: 'full'} ]) ]
Now, let’s create a service file and name it
repository.service.ts
. Place it in the same folder in which environment service resides. In this service, we are going to create get, post, put, and delete requests:
ng g service shared/services/repository --skipTests
So let’s modify repository service:
import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { EnvironmentUrlService } from './environment-url.service'; @Injectable({ providedIn: 'root' }) export class RepositoryService { constructor(private http: HttpClient, private envUrl: EnvironmentUrlService) { } public getData = (route: string) => { return this.http.get(this.createCompleteRoute(route, this.envUrl.urlAddress)); } public create = (route: string, body) => { return this.http.post(this.createCompleteRoute(route, this.envUrl.urlAddress), body, this.generateHeaders()); } public update = (route: string, body) => { return this.http.put(this.createCompleteRoute(route, this.envUrl.urlAddress), body, this.generateHeaders()); } public delete = (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
Excellent.
Let’s explain this code.
First, we are injecting the Angular HttpClient and the environment variable into the constructor. Then we are creating functions that are going to wrap our requests. The getData
function is a wrapper for all GET requests. It accepts the route parameter of type string (api/owner or api/owner/id …) 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, create
, is a wrapper for POST requests. It also generates a route, but additionally receives a body (an entity which we are creating) and generate headers. For this example, we are just creating the Content-Type
inside the header. But if we need additional values inside the header, we could just add another key-value pair inside the HttpHeaders
object.
The update
function is pretty much the same as the create
function, except, it sends the PUT request.
Lastly, the delete
function is a wrapper for the DELETE request which accepts the route like (api/owner/id).
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:
public result: any; constructor(private repo: RepositoryService) { } public consumeGetFromRepository() { this.repo.getData('api/owner/24fd81f8-d58a-4bcc-9f35-dc6cd5641906') .subscribe(res => { this.result = res; }, (error) => { this.handleErrors(error); }) }
As you may notice, we are calling the
getData
function from the repository, but that function won’t be executed until we call the subscribe function. By calling the subscribe function, we are going to execute the getData
function. The result from the response is going to be stored in the parameter
res.
Conclusion
Excellent, now we have our repository prepared and we are ready for creating components, which are going to use this repository functions to show results in a browser.
By reading this post you’ve learned:
- What the HttpClientModule is
- How to work with environment files in Angular
- What the Angular services are
- How to use HTTP requests
- The way to subscribe to HTTP requests
Thank you for reading the post, hopefully, it was helpful to you.
In the next part of the series, I am going to show you how to use lazy content loading in the Angular. Moreover, we are going to show the result data on a page.
Thank you so much for all the work you’ve put into this. You’ve explained a lot of little things I was foggy about. Anyway it’s been extremely useful to go through these 9 steps. I’m looking forward to the rest!
Hi Bob. You are very welcome and thank you for reading these parts and for leaving such a great comment for me. It is always a pleasure to read something like that. I hope the rest of the series is going to be beneficial to you and to all the readers. One more time, thank you very much, mate.
I’ve come back to this guide again – it’s awesome!
I’m creating a single website with multiple projects: .net core Web.API and a separate Angular 6 Web project. However, they will be hosted on the same server as a single application. Do you have some suggestions/or would you change anything in this guide to achieve that?
Thanks for all your effort Marinko. Much appreciated.
Hello Matt. If you take a look at our post where we publish our .NET Core + Angular app, you will see that we publish only one application as well. In a development phase, you are using two projects (.NET Core and Angular) because it is better and cleaner approach (at least that is my opinion) but when it comes to the deployment, you will build all your client files as a production ones and then transfer them to the wwwroot folder in your .NET Core app. Only then you can publish your app.
For more detailed information, you can read: http://34.65.74.140/net-core-web-development-part16/ or http://34.65.74.140/net-core-web-development-part17/
So, I wouldn’t change anything about approach from this tutorial.
I am glad, you find these tutorials useful. Spread the word 😀 😀 And I hope I have helped you with my answer.
All the best.
public result: any;
constructor(private repo: RepositoryService) { }
public consumeGetFromRepository() {
this.repo.getData(‘api/owner/24fd81f8-d58a-4bcc-9f35-dc6cd5641906’)
.subscribe(res => {
this.result = res;
},
(error) => {
this.handleErrors(error);
})
}
where we put this code
Hi Dhruval. You don’t have to place it anywhere. This is just an example how the subscription works. Please read the next artilce from the same series, the link is in the Conclusion section, and you will see how to use this repository in your project.
Hello Sir,
This article very use full me me and everyone but i have one request to make video on it so it’s too much easy to understand. I hope you post video as soon as possible.
Thank you so much
Hey Man!
Thanks for These Great full Tutorials.
On the Repository Service in Every CRUD function you pass this.envUrl.urlAddress as an Parameter
(While its remain same for all CRUD Methods)
Why Not You Send Only route Parameter on Calling from CRUD function
& On createCompleteRoute Function set the default envAddress Value to this.envUrl.urlAddress
——————————————————————–
BEFORE
—————-
public getData = (route: string) => {
return this.http.get(this.createCompleteRoute(route, this.envUrl.urlAddress));
}
private createCompleteRoute = (route: string, envAddress: string) => {
return `${envAddress}/${route}`;
}
——————————————————————–
AFTER
—————-
public getData = (route: string) => {
return this.http.get(this.createCompleteRoute(route));
}
private createCompleteRoute = (route: string, envAddress: string = this.envUrl.urlAddress) => {
return `${envAddress}/${route}`;
}
——————————————————————–
Is There Specific Reason or Something like Best Practice for Above Article Method of Doing This.
Again Thanks for Great Content You Create for Us. ❤
Hello. First of all, you are very welcome and thank you too for all the kind words. There is no any special reason for that, it was just the way I wrote it in that moment. Your solution is great as well and you can use it as-is. I am glad you find our tutorials valuable for you, this is the main purpose for them. Have a great day and Best Regards.
Thanks Man. ❤