> ## Content Index
> Fetch the complete content index at: https://www.angularspace.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Meet HTTP Resource
- URL: https://www.angularspace.com/meet-http-resource/
- Published: 2025-04-14T08:39:11.000Z
- Updated: 2025-04-14T08:39:43.000Z
- Author: Armen Vardanyan
- Tags: Articles

In a [previous article](https://www.angularspace.com/everything-you-need-to-know-abour-resource-for-now/), I have covered the new Resource API, which was added in Angular in version 19 as an experimental feature to promote better approaches with reactive programming. If you have not read that article and are completely unfamiliar with the Resource API completely, I suggest you either read the article or familiarize yourself with the API via the new RFCs the Angular team just published ([RFC 1](https://github.com/angular/angular/discussions/60120?ref=angularspace.com), [RFC 2](https://github.com/angular/angular/discussions/60121?ref=angularspace.com)).

So, if we are on the same page now, let's explore the newest member of Angular's reactivity family: `httpResource`!

## What is `httpResource`?

`httpResource` is a reactive primitive, much like `resource`/`rxResource` from the previous article, but simplified and specifically tailored to work with HTTP GET requests. Why only "GET" requests, one might wonder? Well, we are going to answer this in detail later in the article, so stay tuned!

### The simplest example

So, how does `httpResource` look in action? Let's explore this with a simple example:

```ts
import { httpResource } from '@angular/common/http';

@Component({
  template: `
    @if (users.hasValue()) {
        <ul>
            @for (user of users.value(); track user.id) {
                <li>{{ user.name }}</li>
            }
        </ul>
    } @else if (users.isLoading()) {
        <p>Loading...</p>
    } @else if (users.error()) {
        <button (click)="users.reload()">Retry</button>
    }
  `,
})
export class UserListComponent {
  users = httpResource(() => 'https://jsonplaceholder.typicode.com/users');
}

```

As we can see, `httpResource` returns a `ResourceRef` just like `resource`/`rxResource`, with the same methods and properties like `isLoading`, `hasValue`, `error`, etc (consult the article mentioned above or the RFCs for the full APIs). But, crucially, we write a bit less code, just calling the `httpResource` function with a callback that returns a URL to which the HTTP call will be performed. But why a callback and not just a string? Let us see.

### HTTP resources depending on signals

Now, let us imagine that we are building the "User Details" page, which gets the id of a user via a signal input and fetches the user data from the server. We can use the `httpResource` function to achieve this:

```ts
@Component({
  template: `
    @if (user.hasValue()) {
        <h1>{{ user.value().name }}</h1>
        <p>{{ user.value().email }}</p>
    } @else if (user.isLoading()) {
        <p>Loading...</p>
    } @else if (user.error()) {
        <button (click)="user.reload()">Retry</button>
    }
  `,
})
export class UserDetailsComponent {
  userId = input.required<number>();
  user = httpResource(() => `https://jsonplaceholder.typicode.com/users/${this.userId()}`);
}

```

As we can see, here, we are passing the `userId` signal to the `httpResource` callback, which allows us to fetch the user data based on the signal value. This is powerful, because the callback for `httpResource` is tracking any signals passed to it, so, if, in our example, `userId` changes, the `httpResource` will automatically refetch the user data for the new id from the backend. This makes `httpResource` a great reactive building block, because we can use it simply in one line to create everything we need in regards to HTTP GET requests (which are usually the majority of requests in most applications).

> Note: when one or more of the tracked signals change, the `httpResource` will cancel any current HTTP calls and switch to the new one, similar to how `switchMap` works in RxJS.

By the way, this is even a more powerful tool when combined with Angular's new component-routing input binding, where we can get parameters from the URL as signal inputs and use them in `httpResource`. If you are unfamiliar with component input binding, check [this documentation page](https://angular.dev/api/router/withComponentInputBinding?ref=angularspace.com), but for this particular example, what we need to do is enable the input binding:

```ts
export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(appRoutes, withComponentInputBinding()),
  ]
};

```

And then define the parameters for our component's route:

```ts
export const appRoutes: Routes = [
  { path: 'users/:userId', component: UserDetailsComponent, },
];

```

This was, we can

1. Use parameters from URL as if they were component inputs
2. Load data based on parameters
3. Keep everything in sync if the user navigates to another user's page, changing the `userId` parameter

Now, let us explore what else does this new resource have in store for us.

## What else does `httpResource` has to offer?

As we can see, `httpResource` is working by default with JSON responses - which makes sense, since it is the well-known default for `HttpClient` itself, and `httpResource` is built on top of it. But what if we want to work with other types of responses, like text, blobs, or even custom types?

No worries, `httpResource` has an API similar to `input` signals, where we could specify a required input by doing `input.required<T>()`, and we can do the same with the response type:

```ts
@Component({
  template: `
    @if (data.hasValue()) {
        <pre>{{ data.value() }}</pre>
    } @else if (data.isLoading()) {
        <p>Loading...</p>
    } @else if (data.error()) {
        <button (click)="data.reload()">Retry</button>
    }
  `,
})
export class RawDataComponent {
  fileId = input.required<number>();
  fileResource = httpResource.blob(() => `my-api.url/files/${this.fileId()}`);
}

```

In this case, we would get access to the response as a blob, and can then utilize it using tools like `new File` or `Reader`. Not that we can also get a streamed `ArrayBuffer` using `httpResource.arrayBuffer` or plain text using `httpResource.text`.

## Parsing responses

In the modern web, runtime type validation libraries like [Zod](https://zod.dev/?ref=angularspace.com) are now a crucial part of many applications. If you are unfamiliar with Zod, in short, it is a TypeScript-first schema declaration library, which allows us to do things like this:

```ts
const userSchema = z.object({
  id: z.number(),
  name: z.string(),
  email: z.string().email(),
});

type User = z.infer<typeof userSchema>;

```

Then, we can verify (at runtime!) if certain objects are compliant with a given schema, or parse an object to be assured it is of certain type:

```ts
const user = userSchema.parse({ id: 1, name: 'John Doe', email: 'johndoe@example.com'});

```

One of the popular use cases for Zod and similar tools is verifying HTTP responses; for instance, with Angular's `HttpClient`, we pass an optional type parameter to indicate what kind of response we *expect*, but there is no actual way of verifying it:

```ts
this.http.get<User>('https://jsonplaceholder.typicode.com/users/1').subscribe(user => {
  // user is of type User, but it is not guaranteed to *actually* be this type
  // we can only hope that the server response is correct
});

```

Instead, many developers currently use Zod to verify the response:

```ts
this.http.get('https://jsonplaceholder.typicode.com/users/1').pipe(
  map(response => userSchema.parse(response))
).subscribe(user => {
  // user is of type User, and we are sure that it is correct
});

```

So, `httpResource` makes it way easier to this refinement with Zod or any other validation library by adding a `parse` option when using it:

```ts
export class UserDetailsComponent {
  userId = input.required<number>();
  user = httpResource<User>({
    url: (id: number) => `https://jsonplaceholder.typicode.com/users/${this.userId}`,
    parse: userSchema.parse,
  });
}

```

Now, into the full request API!

## Customized HTTP calls

Sometimes, we need to have a different methods for making requests, and while using "POST" to get the data is not a conventional approach, sometimes we just do not have control over the APIs that have to work with; in that case, we can invoke `httpResource` with a configuration object:

```ts
export class UserDetailsComponent {
  userId = input.required<number>();
  user = httpResource<User>({
    url: () => `https://jsonplaceholder.typicode.com/users/`,
    method: 'POST',
    body: { id: this.userId },
    headers: { 'Content-Type': 'application/json' },
    parse: userSchema.parse,
  });
}

```

On top of this, the `ResourceRef` we get from `httpResource` is actually a specific `HttpResourceRef`, which extends `ResourceRef` with additional methods and properties. Let's see that in action now.

### Reading headers

In some cases, it can be important to access the response headers of a specific HTTP request. For instance, we might want to read the `Content-Type` header to determine how to parse the response. With `httpResource`, we can do this easily:

```ts
@Component({
  template: `
    @if (data.headers().get('Content-Type') === 'application/json') {
        <pre>{{ data.value() | json }}</pre>
    }
  `,
})
export class JsonDataComponent {
  data = httpResource(() => 'my.url');
}

```

The `headers` signal from `HttpResourceRef` is an [HttpHeaders](https://angular.dev/api/common/http/HttpHeaders?ref=angularspace.com) object, giving us the ability to read and check any necessary headers.

### Reading status

Sometimes, the HTTP status can also be important, for example, to determine what specific UI to display in case of an error:

```ts
@Component({
  template: `
    @if (data.status() === 404) {
        <p>Not found</p>
    }
    @if (data.status() === 401) {
        <p>Unauthorized</p>
        <button routerLink="/login">Login</button>
    }
  `,
})
export class StatusComponent {
  data = httpResource(() => 'my.url');
}

```

### Download progress

When downloading large responses (like Blobs) with `httpResource`, sometimes it can be handy to display a progress indicator. We can do this by utilizing the `HttpResourceRef.progress` signal, which returns an [HttpProgressEvent](https://angular.dev/api/common/http/HttpProgressEvent?ref=angularspace.com) object:

```ts
@Component({
  template: `
    @if (data.isLoading()) {
        <p>Downloading...</p>
        <app-progress-bar 
          max="100" 
          [value]="data.progress().loaded / data.progress().total * 100"/>
    }
  `,
})
export class UploadComponent {
  data = httpResource.blob(() => 'my.url');
}

```

> Warning: using the `fetch` implementation of HTTP calls is not capable of sending progress events, so this feature is only available if you do *not* provide the `HttpClient` with the `withFetch` option

> Note: as `httpResource` is designed for retrieving data, you should only use it to download, not upload (files, blobs, etc)

Now, as we familiarized ourselves with the API and structure of `httpResource`, let's see what downsides and concerns it has (at least at this initial stage).

## What are the concerns?

First of all, as mentioned, `httpResource` uses `HttpClient` under the hood, which means that you need to provide it in the application config:

```ts
export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(),
  ],
};

```

This is not a big deal, but if you are, for whatever reason, not using `HttpClient` and utilize something different (maybe straight `fetch` or some library), you will not be able to use `httpResource`, and should instead rely on the `resource` building block:

```ts
export class UserDetailsComponent {
  userId = input.required<number>();
  user = resource<User>({
    request: () => ({id: this.userId()}),
    loader: () => fetch(`https://jsonplaceholder.typicode.com/users/${this.userId}`),
  });
}

```

Next, it is important to understand that `httpResource` makes the requests eagerly, whenever created, meaning it can be trickier to chain requests. For instance, you might load a `Product` object and then want to load other products from a "similar-products" endpoint. With `httpResource`, you would need to create a new `httpResource` instance that depends on the first one, and handle the chaining logic by returning `undefined` while the first request is still loading and the data is yet to become available:

```ts
export class ProductComponent {
  productId = input.required<number>();
  product = httpResource({
    url: (id: number) => `https://my-api.url/products/${this.productId()}`,
    parse: productSchema.parse,
  });
  similarProducts = httpResource<Product[]>({
    url: () => this.product.hasValue() ? 
      `https://my-api.url/products/${this.productId()}/similar` : 
      undefined,
    parse: productSchema.parse,
  });
}

```

So, with this, we covered everything we can know about `httpResource` right now, but a lot of it remains to be seen. In the next section, let us explore the future of resources in Angular to understand how the grand logic of HTTP operations will be shaped.

## Going forward with resources

The Angular team has made it clear that the signals will be the go-to way of working with HTTP-related operations in Angular apps in the future, and Resources are the current thing that supports a part of it. However, currently, it only covers the half of the equation: getting data from a server.

But, as we mentioned, `httpResource` by default uses the "GET" method, and is designed for data retrieval only. Of course, technically, we could force it to use a different method and perform a different operation (like deleting something from the database instead of fetching).

However, philosophically, resources are not suitable for this; they are designed as writable computed signals of which the source data is something on the backend. Deleting something, for example, is not "data" and using resources to represent them is confusing.

So, what are the options? Currently, the Angular team has not settled on one particular approach, but it hasn't stopped Angular enthusiasts from exploring possibilities; let's take a look at some of them now.

For instance, [Tomas Trajan](https://x.com/tomastrajan?ref=angularspace.com) has suggested a concept of `crudResource`, in which all the operations related to a backend entity are encapsulated in a single resource object. Here is an example:

```ts
@Component({ /* ... */ })
export class TodoComponent {
  todos = crudResource<Todo, string>('/todos', {
    strategy: 'optimistic',
    create: { behavior: 'concat' },
    remove: { behavior: 'merge' }
  });

  newTodo = '';

  create() {
    const title = this.newTodo;
    this.newTodo = '';
    this.todos.create({ id: v4(), title, completed: false });
  }

  toggle(todo: Todo) {
    this.todos.update(todo.id, {
      ...todo,
      completed: !todo.completed
    });
  }

  remove(todo: Todo) {
    this.todos.remove(todo.id);
  }
}

```

You can read more about it in Tomas' [tweet](https://x.com/tomastrajan/status/1895375197219512825?ref=angularspace.com) or try it out using the code he provided in [this Github Gist](https://gist.github.com/tomastrajan/6433fbf973adfed0c40ad49ecac6a543?ref=angularspace.com).

While Tomas' approach seeks to replace the `httpResource` with a higher-level building block to encompass all possible operations, a solution proposed by [Marko Stanimirovic](https://x.com/MarkoStDev?ref=angularspace.com) seeks to expand resources with the addition fo a new `httpMutation` primitive, which would cover everything related to other HTTP operations like "update" or "delete". Here is a quick look:

```ts
const updateUser = httpMutation((user: User) => ({
  url: `/users/${user.id}`,
  body: user,
  method: 'PUT',
  onSuccess: () => usersResource.reload(),
  onError: console.error,
}));

// Execute mutation
updateUser.mutate({ id: 1, name: 'Marko' });

// Status
updateUser.isPending();
updateUser.isFulfilled();
updateUser.isError();

```

On top of this, Marko has also proposed an `rxMutation` that leverages the power of RxJS to provide the full range of capabilities that might be necessary when doing such operations:

```ts
// Simple Mutation
const deleteCustomer = rxMutation((id: number) => customersService.delete(id));
deleteCustomer.execute(123);

// With Concurrency Control
const updateCustomer = rxMutation({
  executor: (customer: Customer) => customersService.update(customer),
  operator: concatMap, // mergeMap by default for parallel mutations
  onSuccess: ({ value }) => {
    console.log(`Customer ${value.name} updated successfully`);
  },
  onError: ({ input, error }) => {
    console.error(`Failed to update ${input.name}`, error);
  }
});

```

To better familiarize yourself with these concepts, read Marko's tweets ([here](https://x.com/MarkoStDev/status/1895464855773286891?ref=angularspace.com) and [here](https://x.com/MarkoStDev/status/1896570337866703144?ref=angularspace.com)) and give `rxMutation` a try with this [repository](https://github.com/markostanimirovic/rx-resource-proto?ref=angularspace.com).

> Warning: ideas mentioned in this section are just that: ideas proposed by curios members of the Angular community. They may or may not become a part of Angular itself, so be careful when using them in your projects.

## Conclusion

Starting from v16, signals and everything else that grow out of them (linked signals, resources, etc) have become an incredibly important part of the Angular ecosystem. With the introduction of `httpResource`, we are now able to handle HTTP GET requests in a more reactive and concise way, which is a great step forward in the evolution of the framework.

As mentioned, resources are still experimental, and there is lots of stuff about them that still needs to be added or ironed out. This is why I'd like to encourage readers of this article to also read the RFCs mentioned at the beginning and give feedback and new ideas so we can settle on the best approaches in the future.

## Small Promotion

![Gg2RPJKWwAAHSId.png](https://storage.ghost.io/c/3f/63/3f6333b8-1f83-4017-8426-91bfbc264d81/content/images/2025/01/Gg2RPJKWwAAHSId.png)  
My book, Modern Angular, is now in print! I spent a lot of time writing about every single new Angular feature from v12-v18, including enhanced dependency injection, RxJS interop, Signals, SSR, Zoneless, and way more.

If you work with a legacy project, I believe my book will be useful to you in catching up with everything new and exciting that our favorite framework has to offer. Check it out here: [https://www.manning.com/books/modern-angular](https://www.manning.com/books/modern-angular?ref=angularspace.com)

---

![](https://storage.ghost.io/c/3f/63/3f6333b8-1f83-4017-8426-91bfbc264d81/content/images/2025/04/Screenshot-2024-11-13-at-15--1-_upscayl_2x_high-fidelity-4x.jpg)