Angular Request Augmentation
Published: 2020-06-01 21:39:35

One of the most important packages that come out of the box with angular is the `HTTP` package, although it's incredible and easy to use it still has a limitation when it comes to deal with the Interceptors.

Almost in each Angular project, I used interceptors, at least one interceptor to add Authorization header with every request.
A while back I needed to skip adding that header for a specific request, but unfortunately, there's no direct way to tell the Authorization interceptor, don't add the header to this request!
unless you added a specific header or query param to mark this request.
But this was indirect and not good in the long term, so from this point, I decided to figure out a way to make this more declarative and obvious.

I started to play with request headers, a function that will accept a plain object that will be mapped out to HTTP headers that will be removed before sending the request out of the client, but again I didn't like this approach because it doesn't look as I want.
then I had a chance to extend the `HttpClient` class so I can easily add what I want, I saw a lot of developer doing this approach before releasing the HttpClient to perform some logic before or after sending the request, but this just makes things worst for me.

Thus, I found a way to modify a module interface in order to add specific functionality to it, thanks to [Typescript Module Augmentaion](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation)
it allows you to patch existing objects by importing and then updating them.

So the final thoughts were to extend the `HttpClient`, add a custom method to it to pass custom options along with the request, use DI system to provide the `CustomHttpClient` as `HttpClient`, and finally using Module augmentation to augment the `HttpClient` interface with the new custom method.

Let's start ^^
I'll not dig deep in explaining how you gonna do it, instead, I've combined all the work in one [package](https://github.com/ezzabuzaid/ngx-request-options) and here's the source [code](https://github.com/ezzabuzaid/ngx-request-options) to see how it works in details

1. Run `npm install @ezzabuzaid/ngx-request-options`
2. Define your custom options interface

```
interface CustomOptions {
	defaultUrl:boolean;
	defaultAuth: boolean;
}
```
3. Add `RequestOptionsModule` to `AppModule`

```
import { RequestOptionsModule } from  '@ezzabuzaid/ngx-request-options';

@NgModule({
	imports: [
		HttpClientModule,
		RequestOptionsModule.forRoot<CustomOptions>({
			// Default options to be applied on all requests
			defaultAuth: true;
			defaultUrl: true
		})
	]
})

  
// Add those lines as they are
declare module '@angular/common/http/http' {
	// Augment HttpClient with the new `configure` method
	export  interface  HttpClient {
		/**
		* Configure request options.
		*/
		configure(options: Partial<CustomOptions>): HttpClient;
	}
}
```

4. Time to use it
  * Use the new `configure` before the HTTP method with the options you want to use in the interceptros
```
@Injectable()
export class MyService {
	constructor(private http: HttpClient) { }
	getData() {
		return this.http
			.configure({ defaultUrl:  false })
			.get('endpoint');
	}
}
```
  * Inject the `RequestOptions` in the Interceptor
```
import { RequestOptions } from '@ezzabuzaid/ngx-request-options';
@Injectable()
export class UrlInterceptor implements HttpInterceptor {
	constructor(private requestOptions: RequestOptions<CustomOptions>) { }
	intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
		let  url = request.url;
		if (this.requestOptions.get(request, 'defaultUrl')) {
			url = environment.endpointUrl + request.url;
		}
		return  next.handle(this.requestOptions.clone(request, { url }));
	}
}
```
 
That's it. with this setup, you can have the request communicate will with any interceptor
for more details please refer to the [repo](https://github.com/ezzabuzaid/ngx-request-options)


Some of the use cases of interceptors maybe
* Add default URL to the outgoing request
* Dynamic caching for the response
* Show progress bar while a request on the fly
* Display a snack bar telling the state of the request
* Append Authorization header for a request
* Logging request metadata
* Error handling
* Unify Response content type
* Auto mapping the response body
and there's more,

If you have any questions or feedback please comment about them.

Happy coding!