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.
Marinko, I have this error in repositiry service? In app.module is located import HttpClientModule. Can you help?
Hello Darko. As much as I can see in your file, you are missing these two functions:
As you can inspect in our code snippet and our source code, those functions are inside the repository service file.
Thanks for replay, I inserted these two functions and it’s ok. But I have one more error on second parameter “body” in repository functions?
Try adding the any as a type. You can read here: https://stackoverflow.com/questions/43064221/typescript-ts7006-parameter-xxx-implicitly-has-an-any-type from the accepted answer.
how to work with pagination and get header information in angular api is use same as in your book but paging information is in header provide me complete code for get and post
If you have the second edition of our book, you can find an explanation of how to share your custom header with your client app. If you don’t have it you need to share it with the CORS setup by using the WithExposedHeaders method.
I have your book but i am working in angular how to make a generic repository in angular and how to get header information in angular
You can extract the custom header by using the get function and specifying the header name.
This one is just a simple example from one of my old projects:
const result = await this._repo.getProducts(‘api/products’, this._queryParams);
this.pagination = JSON.parse(result.headers.get(‘X-Pagination’));
this.products = result.body;
actually i have this code already but i want a generic repository for this type of response a batter version like you make in book for core i need same repository and i unit of work for angular project to avoid repetition of code if you have please attach code and also make book on angular project
I am sorry, but we don’t have an example like that. To be honest, in client apps I wouldn’t try to replicate the things I do on the server-side. Just keep it nice and simple, even if you use a separate repo file for each entity.
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. ❤
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
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.
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.
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.