From 5d2db4beb438135796ce4587ac97a70d0b31e600 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Mon, 23 Mar 2020 16:23:56 +0300 Subject: [PATCH 1/5] docs: add how to make HTTP requests using RestService --- docs/en/UI/Angular/Rest-Service.md | 206 +++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 docs/en/UI/Angular/Rest-Service.md diff --git a/docs/en/UI/Angular/Rest-Service.md b/docs/en/UI/Angular/Rest-Service.md new file mode 100644 index 0000000000..f932face22 --- /dev/null +++ b/docs/en/UI/Angular/Rest-Service.md @@ -0,0 +1,206 @@ +# How to Make HTTP Requests + + + +## About HttpClient + +Angular has the amazing [HttpClient](https://angular.io/guide/http) for communication with backend services. It is a layer on top and a simplified representation of [XMLHttpRequest Web API](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest). It also is the recommended agent by Angular for any HTTP request. There is nothing wrong with using the `HttpClient` in your ABP project. + +However, `HttpClient` leaves error handling to the caller (method). In other words, HTTP errors are handled manually and by hooking into the observer of the `Observable` returned. + +```js +getConfig() { + this.http.get(this.configUrl).subscribe( + config => this.updateConfig(config), + error => { + // Handle error here + }, + ); +} +``` + +Although clear and flexible, handling errors this way is repetitive work, even when error processing is delegated to the store or any other injectable. + +An `HttpInterceptor` is able to catch `HttpErrorResponse`  and can be used for a centralized error handling. Nevertheless, cases where default error handler, therefore the interceptor, must be disabled require additional work and comprehension of Angular internals. Check [this issue](https://github.com/angular/angular/issues/20203) for details. + + + +## RestService + +ABP core module has a utility service for HTTP requests: `RestService`. Unless explicitly configured otherwise, it catches HTTP errors and dispatches a `RestOccurError` action. This action is then captured by the `ErrorHandler` introduced by the `ThemeSharedModule`. Since you should already import this module in your app, when the `RestService` is used, all HTTP errors get automatically handled by deafult. + + + +### Getting Started with RestService + +In order to use the `RestService`, you must inject it in your class as a dependency. + +```js +import { RestService } from '@abp/ng.core'; + +@Injectable({ + /* class metadata here */ +}) +class DemoService { + constructor(private rest: RestService) {} +} +``` + +You do not have to provide the RestService` at module or component/directive level, because it is already **provided in root**. + + + +### How to Make a Request with RestService + +You can use the `request` method of the `RestService` is for HTTP requests. Here is an example: + +```js +getFoo(id: number) { + const request: Rest.Request = { + method: 'GET', + url: '/api/some/path/to/foo/' + id, + }; + + return this.rest.request(request); +} +``` + + + +The `request` method always returns an `Observable`. Therefore you can do the following wherever you use `getFoo` method: + +```js +doSomethingWithFoo(id: number) { + this.demoService.getFoo(id).subscribe( + foo => { + // Do something with foo. + } + ) +} +``` + + + +**You do not have to worry about unsubscription.** The `RestService` uses `HttpClient` behind the scenes, so every observable it returns is a finite observable, i.e. it closes subscriptions automatically upon success or error. + + + +As you see, `request` method gets a request options object with `Rest.Request` type. This generic type expects the interface of the request body. You may pass `null` when there is no body, like in a `GET` or a `DELETE` request. Here is an example where there is one: + +```js +postFoo(body: Foo) { + const request: Rest.Request = { + method: 'POST', + url: '/api/some/path/to/foo', + body + }; + + return this.rest.request(request); +} +``` + + + +You may [check here](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/models/rest.ts#L23) for complete `Rest.Request` type, which has only a few chages compared to [HttpRequest](https://angular.io/api/common/http/HttpRequest) class in Angular. + + + +### How to Disable Default Error Handler of RestService + +The `request` method, used with defaults, always handles errors. Let's see how you can change that behavior and handle errors yourself: + +```js +deleteFoo(id: number) { + const request: Rest.Request = { + method: 'DELETE', + url: '/api/some/path/to/foo/' + id, + }; + + return this.rest.request(request, { skipHandleError: true }); +} +``` + + + +`skipHandleError` config option, when set to `true`, disables the error handler and the returned observable starts throwing an error that you can catch in your subscription. + +```js +removeFooFromList(id: number) { + this.demoService.deleteFoo(id).subscribe( + foo => { + // Do something with foo. + }, + error => { + // Do something with error. + } + ) +} +``` + + + +### How to Get a Specific API Endpoint From Application Config + +Another nice config option that `request` method receives is `apiName` (available as of v2.4), which can be used to get a specific module endpoint from application configuration. + + + +```js +putFoo(body: Foo) { + const request: Rest.Request = { + method: 'PUT', + url: '/' + id, + body + }; + + return this.rest.request(request, {apiName: 'foo'}); +} +``` + + + +`putFoo` above will request `https://localhost:44305/api/some/path/to/foo/{id}` as long as the environment variables are as follows: + +```js +// environment.ts + +export const environment = { + apis: { + default: { + url: 'https://localhost:44305', + }, + foo: { + url: 'https://localhost:44305/api/some/path/to/foo', + }, + }, + + /* rest of the environment variables here */ +} +``` + + + +### How to Observe Response Object or HTTP Events Instead of Body + +`RestService` assumes you are generally interested in the body of a response and, by default, sets `observe` property as `'body'`. However, there may be times you are rather interested in something else, such as a custom proprietary header. For that, the `request` method receives `observe` property in its config object. + +```js +getSomeCustomHeaderValue() { + const request: Rest.Request = { + method: 'GET', + url: '/api/some/path/that/sends/some-custom-header', + }; + + return this.rest.request>( + request, + {observe: Rest.Observe.Response}, + ).pipe( + map(response => response.headers.get('Some-Custom-Header')) + ); +} +``` + + + +You may find `Rest.Observe` enum [here](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/models/rest.ts#L10). + From 9defbd82b9e71a1d1a44b1f88501acf860d3ccf3 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Tue, 24 Mar 2020 09:12:12 +0300 Subject: [PATCH 2/5] docs: rename http request document as Http-Requests.md --- docs/en/UI/Angular/{Rest-Service.md => Http-Requests.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/en/UI/Angular/{Rest-Service.md => Http-Requests.md} (100%) diff --git a/docs/en/UI/Angular/Rest-Service.md b/docs/en/UI/Angular/Http-Requests.md similarity index 100% rename from docs/en/UI/Angular/Rest-Service.md rename to docs/en/UI/Angular/Http-Requests.md From 09cb5ec600c3597742553c39cfa62c34d0c06093 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 24 Mar 2020 09:41:41 +0300 Subject: [PATCH 3/5] docs: add what's next to Http-Requests.md --- docs/en/UI/Angular/Http-Requests.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/en/UI/Angular/Http-Requests.md b/docs/en/UI/Angular/Http-Requests.md index f932face22..71878c8045 100644 --- a/docs/en/UI/Angular/Http-Requests.md +++ b/docs/en/UI/Angular/Http-Requests.md @@ -46,7 +46,7 @@ class DemoService { } ``` -You do not have to provide the RestService` at module or component/directive level, because it is already **provided in root**. +You do not have to provide the `RestService` at module or component/directive level, because it is already **provided in root**. @@ -146,7 +146,7 @@ Another nice config option that `request` method receives is `apiName` (availabl ```js -putFoo(body: Foo) { +putFoo(body: Foo, id: string) { const request: Rest.Request = { method: 'PUT', url: '/' + id, @@ -204,3 +204,6 @@ getSomeCustomHeaderValue() { You may find `Rest.Observe` enum [here](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/models/rest.ts#L10). +## What's Next? + +* [Localization](./Localization.md) \ No newline at end of file From 4a7bd00eed4f324059dd382aa291cdfbd3253b55 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 24 Mar 2020 09:41:57 +0300 Subject: [PATCH 4/5] docs: add what's next to Localization.md --- docs/en/UI/Angular/Localization.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/en/UI/Angular/Localization.md b/docs/en/UI/Angular/Localization.md index 01394a3fea..d627f466ba 100644 --- a/docs/en/UI/Angular/Localization.md +++ b/docs/en/UI/Angular/Localization.md @@ -133,4 +133,8 @@ Localization resources are stored in the `localization` property of `ConfigState ## See Also -* [Localization in ASP.NET Core](../../Localization.md) \ No newline at end of file +* [Localization in ASP.NET Core](../../Localization.md) + +## What's Next? + +* [Permission Management](./Permission-Management.md) \ No newline at end of file From b626a9170f86069cc01e1ad14954c1d2327af57f Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 24 Mar 2020 09:42:24 +0300 Subject: [PATCH 5/5] docs: add Http Requests to navigation as a menu item --- docs/en/docs-nav.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 5c2c3a8e64..a96fb911d2 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -312,6 +312,10 @@ { "text": "Angular", "items": [ + { + "text": "HTTP Requests", + "path": "UI/Angular/HTTP-Requests.md" + }, { "text": "Localization", "path": "UI/Angular/Localization.md"