Marcin Jahn | Dev Notebook
  • Home
  • Programming
  • Technologies
  • Projects
  • About
  • Home
  • Programming
  • Technologies
  • Projects
  • About
  • An icon of the Core section Core
    • Programs Execution
    • Stack and Heap
    • Asynchronous Programming
      • Overview
      • Event Queues
      • Fibers
      • Stackless Coroutines
  • An icon of the .NET section .NET
    • HTTPClient
    • Async
      • How Async Works
      • TAP Tips
    • Equality
    • Comparisons
    • Enumerables
    • Unit Tests
    • Generic Host
    • Logging
    • Configuration
    • Records
    • Nullability
    • Garbage Collector
    • IL and Allocations
    • gRPC
    • Source Generators
    • Platform Invoke
    • ASP.NET Core
      • Overview
      • Middleware
      • Razor Pages
      • Routing in Razor Pages
      • Web APIs
      • Filters
      • Identity
      • Validation
      • Tips
    • Entity Framework Core
      • Overview
      • Testing
      • Tips
  • An icon of the Angular section Angular
    • Overview
    • Components
    • Directives
    • Services and DI
    • Routing
    • Observables (RxJS)
    • Forms
    • Pipes
    • HTTP
    • Modules
    • NgRx
    • Angular Universal
    • Tips
    • Standalone Components
  • An icon of the JavaScript section JavaScript
    • OOP
    • JavaScript - The Weird Parts
    • JS Functions
    • ES Modules
    • Node.js
    • Axios Tips
    • TypeScript
      • TypeScript Environment Setup
      • TypeScript Tips
    • React
      • React Routing
      • MobX
    • Advanced Vue.js Features
  • An icon of the Rust section Rust
    • Overview
    • Cargo
    • Basics
    • Ownership
    • Structures
    • Enums
    • Organization
    • Collections
    • Error Handling
    • Generics
    • Traits
    • Lifetimes
    • Closures
    • Raw Pointers
    • Smart Pointers
    • Concurrency
    • Testing
    • Tips
  • An icon of the C/C++ section C/C++
    • Compilation
    • Structures
    • OOP in C
    • Pointers
    • Strings
    • Dynamic Memory
    • argc and argv Visualization
  • An icon of the GTK section GTK
    • Overview
    • GObject
    • GJS
  • An icon of the CSS section CSS
    • Responsive Design
    • CSS Tips
    • CSS Pixel
  • An icon of the Unity section Unity
    • Unity
  • An icon of the Functional Programming section Functional Programming
    • Fundamentals of Functional Programming
    • .NET Functional Features
    • Signatures
    • Function Composition
    • Error Handling
    • Partial Application
    • Modularity
    • Category Theory
      • Overview
      • Monoid
      • Other Magmas
      • Functors
  • An icon of the Algorithms section Algorithms
    • Big O Notation
    • Array
    • Linked List
    • Queue
    • Hash Table and Set
    • Tree
    • Sorting
    • Searching
  • An icon of the Architecture section Architecture
    • What is architecture?
    • Domain-Driven Design
    • ASP.NET Core Projects
  • An icon of the Core section Core
    • Programs Execution
    • Stack and Heap
    • Asynchronous Programming
      • Overview
      • Event Queues
      • Fibers
      • Stackless Coroutines
  • An icon of the .NET section .NET
    • HTTPClient
    • Async
      • How Async Works
      • TAP Tips
    • Equality
    • Comparisons
    • Enumerables
    • Unit Tests
    • Generic Host
    • Logging
    • Configuration
    • Records
    • Nullability
    • Garbage Collector
    • IL and Allocations
    • gRPC
    • Source Generators
    • Platform Invoke
    • ASP.NET Core
      • Overview
      • Middleware
      • Razor Pages
      • Routing in Razor Pages
      • Web APIs
      • Filters
      • Identity
      • Validation
      • Tips
    • Entity Framework Core
      • Overview
      • Testing
      • Tips
  • An icon of the Angular section Angular
    • Overview
    • Components
    • Directives
    • Services and DI
    • Routing
    • Observables (RxJS)
    • Forms
    • Pipes
    • HTTP
    • Modules
    • NgRx
    • Angular Universal
    • Tips
    • Standalone Components
  • An icon of the JavaScript section JavaScript
    • OOP
    • JavaScript - The Weird Parts
    • JS Functions
    • ES Modules
    • Node.js
    • Axios Tips
    • TypeScript
      • TypeScript Environment Setup
      • TypeScript Tips
    • React
      • React Routing
      • MobX
    • Advanced Vue.js Features
  • An icon of the Rust section Rust
    • Overview
    • Cargo
    • Basics
    • Ownership
    • Structures
    • Enums
    • Organization
    • Collections
    • Error Handling
    • Generics
    • Traits
    • Lifetimes
    • Closures
    • Raw Pointers
    • Smart Pointers
    • Concurrency
    • Testing
    • Tips
  • An icon of the C/C++ section C/C++
    • Compilation
    • Structures
    • OOP in C
    • Pointers
    • Strings
    • Dynamic Memory
    • argc and argv Visualization
  • An icon of the GTK section GTK
    • Overview
    • GObject
    • GJS
  • An icon of the CSS section CSS
    • Responsive Design
    • CSS Tips
    • CSS Pixel
  • An icon of the Unity section Unity
    • Unity
  • An icon of the Functional Programming section Functional Programming
    • Fundamentals of Functional Programming
    • .NET Functional Features
    • Signatures
    • Function Composition
    • Error Handling
    • Partial Application
    • Modularity
    • Category Theory
      • Overview
      • Monoid
      • Other Magmas
      • Functors
  • An icon of the Algorithms section Algorithms
    • Big O Notation
    • Array
    • Linked List
    • Queue
    • Hash Table and Set
    • Tree
    • Sorting
    • Searching
  • An icon of the Architecture section Architecture
    • What is architecture?
    • Domain-Driven Design
    • ASP.NET Core Projects

HTTP Requests in Angular

Angular comes with a built-in HTTP client. That’s a difference compared to Vue.js or React, which do not provide such tooling.

In order to use the built-in client, it needs to be imported into your module. You need to import the HttpClientModule. With that in place, we can inject the HTTP client into our classes, kind of similar to how we’d do in .NET.

export class MyComponent {
constructor(private httpClient: HttpClient) { }
}

The HttpClient has methods corresponding to actual HTTP methods, e.g.:

httpClient.get<Person>('api.com')
.subscribe(response => {
// read response...
});
httpClient.post<Person>('api.com', { name: 'Marcin' })
.subsribe(response => {
// read response...
});

By default, all these methods return an Observable. We can use operators on them. Error handling is also the same as in Observables.

The requests will actually NOT be sent out if nothing subscribes to the returned Observable!

We do not have to unsubscribe() from the observable, it’s managed by Angular.

Body

Angular will serialize objects that should be sent as a body of the request behind the scenes.

Each method accepts an options object, which is the last parameter. There, we can set things such as headers, query parameters, etc.

Raw Response

By default, the subscrition returned when inoking an HTTP request, resolves to an object representing the body of the response. In some cases, we might need more data, like response headers or the status code. It can be configured via the options object. Here’s an example:

let sub = httpClient.get("api.com", {
observe: 'response' // 'body' by default
})

Events

We can also observe 'events' This one will bring multiple messages to subscribers, informing about the stages that the request is at (e.g. Sent, Response, etc.).

This seems to be the only useful use of Observables for HTTP requests, and a very niche one. Otherwise, I don’t really see why Promises wouldn’t be utilized by default.

Response String

Angular automatically converts the responses to JS objects. We can tell it not to do it:

let sub = httpClient.get("api.com", {
responseType: 'text' // 'json' by default
})

It can’t be used iwth generic versions of HTTP client’s methods, it wouldn’t make sense anyway, because the whole point of these generics is to automatically get a typed response.

Interceptors

Interceptors allow us to set up some global action on outgoing HTTP requests and/or incoming HTTP responses. They work a bit like middleware in ASP.NET Core. Interceptors are created as services implementing HttpInterceptor.

Request Interceptors

export class MyInterceptorService implements HttpInterceptor {
interpcet(request: HttpRequest<any>, next: HttpHandler) {
// do something with the request (log, attach some headers, etc.)
return next.handle(request); // send the request further down the pipeline
}
}

The request argument is generic. If we know the type of the respones, we can use it here instead of any.

Here’s how we register interceptors. In the module, we’d do:

@NgModule({
declaractions: [ AppComponent ],
imports: [ BrowserModule, HttpClientModule ],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: MyInterceptorService,
multi: true // with this, we can have multiple interceptors
}
]
})
export class AppModule {}

What we’re doing above is just the DI. We treat HTTP_INTERCEPTORS as a placeholder for actual interceptors. Angular’s inner code asks for HTTP_INTERCEPTORS and it is given whatever we register.

Multiple Interceptors

Here’s how we’d register multiple interceptors:

providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: MyInterceptorService,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: AnotherInterceptorService,
multi: true
}
]

The order of execution of the interceptors pipeline is the same as the order of their registration.

In order to restrict the interceptor only to some sub-group of requests, we need to filter requests out in the interceptor itself. All the interceptors are invoked for any HTTP request.

Response Interceptors

Intercepting incoming responses uses the same kind of services as shown previously. This time though, we need to makse use of the fact that the second parameter of the interceptor returns an Observable. It is going to notify us of the lifetime of the request.

export class MyInterceptorService implements HttpInterceptor {
interpcet(request: HttpRequest<any>, next: HttpHandler) {
return next.handle(request).pipe(tap(event => {
// do something...
}))
}
}

The event that we get access to is the same kind of event that was mentioned in Raw Response section. We might want to filter out all the events that are not of type equal to Response. The interceptor may modify the response or do anything else with it.

RxJS tap

tap is an operator that allows us to do some action on every event, but it does not transform the event in any way (like map would do for example).

Promise

Instead of using Observables, we can utilize Promises, making it possile to use async/await in our code:

let promise = httpClient.get<Stuff>('api.com').toPromise();
await promise;

Best Practices

Services

Instead of using HttpClient in our components directly, it makes more sense to put that logic into some service. Such a service would work like a kind of repository for a specific kind of data being fetched.

←  Pipes
Modules  →
© 2023 Marcin Jahn | Dev Notebook | All Rights Reserved. | Built with Astro.