{"id":27404,"date":"2024-12-18T16:33:39","date_gmt":"2024-12-18T15:33:39","guid":{"rendered":"https:\/\/www.angulararchitects.io\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/"},"modified":"2025-06-04T11:24:48","modified_gmt":"2025-06-04T09:24:48","slug":"using-the-resource-api-with-the-ngrx-signal-store","status":"publish","type":"post","link":"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/","title":{"rendered":"Using Angular&#8217;s Resource API with the NGRX Signal Store"},"content":{"rendered":"<div class=\"wp-post-series-box series-ngrx-signal-store-en wp-post-series-box--expandable\">\n\t\t\t<input id=\"collapsible-series-ngrx-signal-store-en69daaa227ff4d\" class=\"wp-post-series-box__toggle_checkbox\" type=\"checkbox\">\n\t\n\t<label\n\t\tclass=\"wp-post-series-box__label\"\n\t\t\t\t\tfor=\"collapsible-series-ngrx-signal-store-en69daaa227ff4d\"\n\t\t\ttabindex=\"0\"\n\t\t\t\t>\n\t\t<p class=\"wp-post-series-box__name wp-post-series-name\">\n\t\t\tThis is post 5 of 7 in the series <em>&ldquo;NGRX Signal Store&rdquo;<\/em>\t\t<\/p>\n\t\t\t<\/label>\n\n\t\t\t<div class=\"wp-post-series-box__posts\">\n\t\t\t<ol>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/the-new-ngrx-signal-store-for-angular-2-1-flavors\/\">The new NGRX Signal Store for Angular: 3+n Flavors<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/smarter-not-harder-simplifying-your-application-with-ngrx-signal-store-and-custom-features\/\">Smarter, Not Harder: Simplifying your Application With NGRX Signal Store and Custom Features<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/ngrx-signal-store-deep-dive-flexible-and-type-safe-custom-extensions\/\">NGRX Signal Store Deep Dive: Flexible and Type-Safe Custom Extensions<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/the-ngrx-signal-store-and-your-architecture\/\">The NGRX Signal Store and Your Architecture<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><span class=\"wp-post-series-box__current\">Using Angular&#8217;s Resource API with the NGRX Signal Store<\/span><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/the-new-event-api-for-the-ngrx-signal-store-a-quantum-of-redux\/\">The new Event API for the NgRx Signal Store: A Quantum of Redux<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/full-cycle-reativity-in-angular-signal-forms-signal-store-resources-mutation-api\/\">Full-Cycle Reactivity in Angular: Signal Forms, Signal Store, Resources, &#038; Mutation API<\/a><\/li>\n\t\t\t\t\t\t\t<\/ol>\n\t\t<\/div>\n\t<\/div>\n<p>With version 19, NgRx introduced the <code>withProps<\/code> feature that allows us to add arbitrary properties to the Store. With this feature, the Store can, for instance, define central services, Observables, or Resources.<\/p>\n<p>This article shows how to use <code>withProps<\/code> to leverage the new Resource API inside a Signal Store. This allows the Store to provide the usual reactive behavior and to prevent race conditions without RxJS. For connecting a template-driven form to the Store, the example is using <code>linkedSignal<\/code> together with the Signal Store's new <code>signalMethod<\/code> helper.<\/p>\n<p>\ud83d\udcc2 <a href=\"https:\/\/github.com\/manfredsteyer\/desserts.git\">Source Code<\/a> (see branch <em>08b-details<\/em>)<\/p>\n<h2>Reactive Flow<\/h2>\n<p>For demonstrating the usage of the Resource API inside of a Signal Store, I'm using the dessert application known from other blog posts:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2024\/12\/example-app.jpg\" alt=\"Example Application\" \/><\/p>\n<p>The filters -- Original Name, and English Name -- trigger the reactive flow, resulting in the displayed rated desserts. Also, clicking the shown button makes the store to load ratings for the currently shown desserts.<\/p>\n<p>Before we start, I'd like to visualize this flow as a simple reactive graph:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2024\/12\/reactive-graph.png\" style=\"width: 100%; max-width:800px\"><\/p>\n<p>As we see here, the Store can receive the consumer's (e.g., the Component's) intention via the three methods displayed on the left. The <code>filter<\/code> Signal triggers the <code>dessertsResource<\/code>: Every time it's changed, the resource loads desserts.<\/p>\n<p>The <code>ratingsResource<\/code> is directly triggered by the <code>loadRatings<\/code> method, and the <code>updateRatings<\/code> method updates this Resource's local working copy. Another method not shown here could write back this working copy to the backend.<\/p>\n<h2>Consumer's Perspective<\/h2>\n<p>Now, let's have a look at the Store's external view by investigating the component that consumes it:<\/p>\n<pre><code class=\"language-typescript\">@Component([...])\nexport class DessertsComponent {\n  #store = inject(DessertStore);\n\n  originalName = linkedSignal(() =&gt; this.#store.filter.originalName());\n  englishName = linkedSignal(() =&gt; this.#store.filter.englishName());\n\n  ratedDesserts = this.#store.ratedDesserts;\n  loading = this.#store.loading;\n\n  #linkedFilter = computed(() =&gt; ({\n    originalName: this.originalName(),\n    englishName: this.englishName()\n  }));\n\n  constructor() {\n    this.#store.updateFilter(this.#linkedFilter)\n  }\n\n  loadRatings(): void {\n    this.#store.loadRatings();\n  }\n\n  updateRating(id: number, rating: number): void {\n    this.#store.updateRating(id, rating);\n  }\n}<\/code><\/pre>\n<p>As the example binds the filter, <code>originalName<\/code> and <code>englishName<\/code>, to a template-driven form, the Component wraps them in Linked Signals. This allows it to use <code>ngModel<\/code> with a two-way binding:<\/p>\n<pre><code class=\"language-html\">&lt;input [(ngModel)]=&quot;originalName&quot; name=&quot;originalName&quot; \/&gt;\n&lt;input [(ngModel)]=&quot;englishName&quot; name=&quot;englishName&quot; \/&gt;<\/code><\/pre>\n<p>In this case, the two-way binding updates the local working copy provided by the Linked Signal. To ensure this working copy is sent back to the Store, the constructor passes it to the Store's <code>updateFilter<\/code> method.<\/p>\n<p>It's essential to see that <code>updateFilter<\/code> does not just receive the current filter but a computed <code>linkedFilter<\/code> Signal. As we will see below, this method is a so-called Signal Method that runs every time the passed signal changes. This allows the example of keeping the filter in the store up to date.<\/p>\n<p>Admittedly, a reactive Form would make it easier to synchronize the form with the Store.<\/p>\n<h2>The Store<\/h2>\n<p>If we look at the Store's internal view, we see that the state represents the filter:<\/p>\n<pre><code class=\"language-typescript\">export type Requested = undefined | true;\n\nexport const DessertStore = signalStore(\n  { providedIn: &#039;root&#039; },\n  withState({\n    filter: {\n      originalName: &#039;&#039;,\n      englishName: &#039;Cake&#039;,\n    },\n    ratingsRequested: undefined as Requested\n  }),\n [...],\n);<\/code><\/pre>\n<p>Properties for the loaded desserts and ratings are missing here. The below-discussed Resources provide them. Also, the loading state can be derived from them. As we don't have parameters for loading the ratings, just a flag <code>ratingsRequested<\/code> is used. <\/p>\n<h2>Getting Services via withProps<\/h2>\n<p>The next feature added to the Store is <code>withProps<\/code>. The Store uses it to inject services we need later for setting up Resources and methods:<\/p>\n<pre><code class=\"language-typescript\">export const DessertStore = signalStore(\n  [...],\n  withProps(() =&gt; ({\n    _dessertService: inject(DessertService),\n    _ratingService: inject(RatingService),\n    _toastService: inject(ToastService),\n  })),\n  [...],\n);<\/code><\/pre>\n<p>This streamlines the Store's implementation a bit. Before we got <code>withProps<\/code>, such services had to be injected into parameters added to the individual features. As this resulted in long parameter lists and needed to be repeated for different features the same service was used in, leveraging <code>withProps<\/code> for this task seems more fitting.<\/p>\n<p>Please also note that the property names introduced here start with an <strong>underscore.<\/strong> By convention, the Signal Store considers such properties as <strong>private<\/strong> and does not expose them to the consumer.<\/p>\n<h2>Setting up Resources<\/h2>\n<p>For setting up the Resources, the Store uses another <code>withProps<\/code> section:<\/p>\n<pre><code class=\"language-typescript\">export const DessertStore = signalStore(\n  [...],\n  withProps((store) =&gt; ({\n    _dessertsResource: resource({\n      params: store.filter,\n      loader: (loaderParams) =&gt; {\n        const filter = loaderParams.params;\n        const abortSignal = params.abortSignal;\n        return store._dessertService.findPromise(filter, abortSignal);\n      },\n    }),\n    _ratingsResource: resource({\n      params: store.ratingsRequested\n      loader: (loaderParams) =&gt; {\n        const abortSignal = loaderParams.abortSignal;\n        return store._ratingService.loadExpertRatingsPromise(abortSignal);\n      }\n    })\n  })),\n  [...],\n);<\/code><\/pre>\n<p>As the <code>withProps<\/code> section with the Resources is defined after the one with the services, the Resources can access these services. The <code>_dessertsResource<\/code> uses the filter in the Store's state as its <code>params<\/code>. Hence, a change to the filter triggers loading desserts.<\/p>\n<h2>More on this: Angular Architecture Workshop (online, interactive, advanced)<\/h2>\n<p>Become an expert for enterprise-scale and maintainable Angular applications with our <a href=\"https:\/\/www.angulararchitects.io\/en\/angular-workshops\/advanced-angular-enterprise-architecture-incl-ivy\/\">Angular Architecture workshop!<\/a><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/sujet-en.jpg\" alt=\"\" \/><\/p>\n<p><a href=\"https:\/\/www.angulararchitects.io\/en\/angular-workshops\/advanced-angular-enterprise-architecture-incl-ivy\/\">All Details (English Version)<\/a> | <a href=\"https:\/\/www.angulararchitects.io\/schulungen\/advanced-angular-enterprise-anwendungen-und-architektur\/\">All Details (German Version)<\/a><br \/>\n<\/p>\n<h2>Optional: Exposing Read-Only Resources<\/h2>\n<p>Like the injected services, the Resources discussed in the previous section are marked as private. In this example, they are just an implementation detail: The consumer does not care whether the data is loaded via the Resource API, RxJS, or in a different way.<\/p>\n<p>However, if we wanted to provide the Resources to the consumer, we could add another <code>withProps<\/code> section exposing read-only versions of them:<\/p>\n<pre><code class=\"language-typescript\">export const DessertStore = signalStore(\n  [...],\n  withProps((store) =&gt; ({\n    dessertsResource: store._dessertsResource.asReadonly(),\n    ratingsResource: store._ratingsResource.asReadonly(),\n  })),\n  [...],\n);<\/code><\/pre>\n<p>A read-only resource provides the loaded data, the loading state, and error information but does not allow updating of the local working copy. This idea of defining private resources that are exposed as public read-only resources might be automated by a custom feature like <code>withResource<\/code>.<\/p>\n<h2>Deriving View Models<\/h2>\n<p>To derive view models that are displayed via data binding, the Store introduces some computed Signals:<\/p>\n<pre><code class=\"language-typescript\">export const DessertStore = signalStore(\n  [...],\n  withComputed((store) =&gt; ({\n    ratedDesserts: computed(() =&gt; toRated(\n      store._dessertsResource.value(),\n      store._ratingsResource.value()\n    )),\n    loading: computed(() =&gt;\n      store._dessertsResource.isLoading()\n        || store._dessertsResource.isLoading())\n  })),\n  [...]\n);<\/code><\/pre>\n<p>The helper function <code>toRated<\/code> (not shown here) combines the desserts with the loaded ratings. The <code>loading<\/code> Signal returns <code>true<\/code> when one of the resources is in a loading state.<\/p>\n<h2>Providing Methods<\/h2>\n<p>As the Resource API gives us a reactive and hence a declarative way for loading data, there is not much imperative code left for the methods:<\/p>\n<pre><code class=\"language-typescript\">export const DessertStore = signalStore(\n  [...],\n  withMethods((store) =&gt; ({\n    updateFilter: signalMethod&lt;DessertFilter&gt;((filter) =&gt; {\n      patchState(store, { filter });\n    }),\n    loadRatings: () =&gt; {\n        patchState(store, { ratingsRequested: true });\n        store._ratingsResource.reload();\n    },\n    updateRating: (id: number, rating: number) =&gt; {\n      store._ratingsResource.update(ratings =&gt; ({\n        ...ratings,\n        [id]: rating,\n      }));\n    },\n  })),\n  [...],\n);<\/code><\/pre>\n<p>These methods mainly write the passed values into the Store. The method <code>updateFilter<\/code> is set up with the new <code>signalMethod<\/code> helper. As the example is using <code>signalMethod&lt;DessertFilter&gt;<\/code>, the method takes a <code>DessertFilter<\/code> or a <code>Signal&lt;DessertFilter&gt;<\/code>. In the latter case, the defined method runs every time the passed Signal changes.<\/p>\n<p>While the passed Signal is tracked, the method's <strong>implementation is untracked<\/strong> (!) by convention. Hence, it is not re-executed when a Signal in one of the called methods is changing. Usually, this behavior is desirable as it allows us to see at first glance when the method's implementation runs.<\/p>\n<p>The helper <code>signalMethod<\/code> is similar to <code>rxMethod<\/code>, already introduced with the initial version of the Signal Store. However, <code>signalMethod<\/code> does not rely on RxJS. This also means we need to take care of preventing race conditions by ourselves. In the example shown here, this task is handled by the Resource API.<\/p>\n<p>The <code>loadRatings<\/code> method triggers the <code>_ratingsResource<\/code> by setting the flag <code>ratingsRequested<\/code> to true and calling <code>reload<\/code>. This approach has already been discussed <a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/asynchronous-resources-with-angulars-new-resource-api\/\">here<\/a>. The method <code>updateRating<\/code> updates the Resource's local working copy. I admit, this feels a bit strange because a store usually does not directly modify writable signals. However, this aligns with the idea of local working copies provided by <code>linkedSignal<\/code> and the Resource API: Directly updating temporary data inside the reactive flow. Perhaps we will find a more streamlined way to accomplish this task.<\/p>\n<h2>Error Handling with Hooks and Effects<\/h2>\n<p>If loading data does not work, the Resource informs about the current situation via its <code>error<\/code> Signal. To display a respective toast message, the Store sets up an <code>onInit<\/code> hook with an Effect tracking the <code>error<\/code>:<\/p>\n<pre><code class=\"language-typescript\">export const DessertStore = signalStore(\n [...],\n  withHooks({\n    onInit(store) {\n      const toastService = store._toastService;\n      const dessertsError = store._dessertsResource.error;\n\n      effect(() =&gt; {\n        const error = store._dessertsResource.error;\n        if (error) {\n          store._toastService.show(&#039;Error: &#039; + getMessage(error));\n        }\n      });\n    }\n  })\n);<\/code><\/pre>\n<p>The method <code>getMessage<\/code> returns an error message derived from the <code>error<\/code> object:<\/p>\n<pre><code class=\"language-typescript\">export function getMessage(error: unknown) {\n  if (error &amp;&amp; typeof error === &quot;object&quot; &amp;&amp; &quot;message&quot; in error) {\n    return error.message;\n  }\n  return String(error);\n}<\/code><\/pre>\n<p>To make it easy to repeat this task for further <code>error<\/code> Signals, we could move the Effect into a helper function:<\/p>\n<pre><code class=\"language-typescript\">export const DessertStore = signalStore(\n  [...],\n  withHooks({\n    onInit(store) {\n      const toastService = store._toastService;\n      const dessertsError = store._dessertsResource.error;\n      const ratingsError = store._ratingsResource.error;\n\n      displayErrorEffect(dessertsError, toastService);\n      displayErrorEffect(ratingsError, toastService);\n    }\n  })\n);<\/code><\/pre>\n<p>This helper function takes the <code>errorSignal<\/code> and the <code>toastService<\/code> and sets up the Effect shown before:<\/p>\n<pre><code class=\"language-typescript\">export function displayErrorEffect(\n  errorSignal: Signal&lt;unknown&gt;,\n  toastService: ToastService\n) {\n  effect(() =&gt; {\n    const error = errorSignal();\n    if (error) {\n      toastService.show(&quot;Error: &quot; + getMessage(error));\n    }\n  });\n}<\/code><\/pre>\n<h2>Everything Together<\/h2>\n<p>Now, that we've discussed all the sections of a Signal Store utilizing the Resource API, let's have a look at the full store implementation:<\/p>\n<pre><code class=\"language-typescript\">export const DessertStore = signalStore(\n  { providedIn: &quot;root&quot; },\n  withState({\n    filter: {\n      originalName: &quot;&quot;,\n      englishName: &quot;Cake&quot;,\n    },\n  }),\n  withProps(() =&gt; ({\n    _dessertService: inject(DessertService),\n    _ratingService: inject(RatingService),\n    _toastService: inject(ToastService),\n  })),\n  withProps((store) =&gt; ({\n    _dessertsResource: resource({\n      request: Store.filter,\n      loader: (params) =&gt; {\n        const filter = params.request;\n        const abortSignal = params.abortSignal;\n        return store._dessertService.findPromise(filter, abortSignal);\n      },\n    }),\n    _ratingsResource: resource({\n      loader: (params) =&gt; {\n        const abortSignal = params.abortSignal;\n        return store._ratingService.loadExpertRatingsPromise(abortSignal);\n      },\n    }),\n  })),\n  withProps((store) =&gt; ({\n    dessertsResource: store._dessertsResource.asReadonly(),\n    ratingsResource: store._ratingsResource.asReadonly(),\n  })),\n  withComputed((store) =&gt; ({\n    ratedDesserts: computed(() =&gt;\n      toRated(store._dessertsResource.value(), store._ratingsResource.value())\n    ),\n    loading: computed(\n      () =&gt;\n        store._dessertsResource.isLoading() ||\n        store._dessertsResource.isLoading()\n    ),\n  })),\n  withMethods((store) =&gt; ({\n    updateFilter: signalMethod&lt;DessertFilter&gt;((filter) =&gt; {\n      patchState(store, { filter });\n    }),\n    loadRatings: () =&gt; {\n      store._ratingsResource.reload();\n    },\n    updateRating: (id: number, rating: number) =&gt; {\n      store._ratingsResource.update((ratings) =&gt; ({\n        ...ratings,\n        [id]: rating,\n      }));\n    },\n  })),\n  withHooks({\n    onInit(store) {\n      const toastService = store._toastService;\n      const dessertsError = store._dessertsResource.error;\n      const ratingsError = store._ratingsResource.error;\n\n      displayErrorEffect(dessertsError, toastService);\n      displayErrorEffect(ratingsError, toastService);\n    },\n  })\n);<\/code><\/pre>\n<h2>Discussion and Outlook<\/h2>\n<p>Thanks to <code>withProps<\/code> introduced with NgRx 19, a Signal Store can define arbitrary properties. This streamlines working with injected services and allows setting up Resources. The store can use such Resources as implementation details or expose them to the consumer. In the latter case, the Resource should be made read-only for the outside.<\/p>\n<p>Directly using the Resource API inside a Signal Store allows us to define a reactive dataflow fully using Angular's Signal API. The new <code>signalMethod<\/code> helper can be used to connect signals to the Store.<\/p>\n<p>As a Resource provides a local working copy of the loaded data, it can be overwritten with updates provided by the user before it is sent back to the server. Directly updating this working copy feels a bit strange, as usually, the Store does not directly modify writable Signals. However, as discussed above, temporarily updating data inside the reactive graph is part of the idea behind such working copies. Perhaps the community eventually finds a better way to accomplish this task. Also, there might be some value in a <code>withResource<\/code> feature for defining a private Resource exposed as read-only.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is post 5 of 7 in the series &ldquo;NGRX Signal Store&rdquo; The new NGRX Signal Store for Angular: 3+n Flavors Smarter, Not Harder: Simplifying your Application With NGRX Signal Store and Custom Features NGRX Signal Store Deep Dive: Flexible and Type-Safe Custom Extensions The NGRX Signal Store and Your Architecture Using Angular&#8217;s Resource API [&hellip;]<\/p>\n","protected":false},"author":9,"featured_media":27402,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_price":"","_stock":"","_tribe_ticket_header":"","_tribe_default_ticket_provider":"","_ticket_start_date":"","_ticket_end_date":"","_tribe_ticket_show_description":"","_tribe_ticket_show_not_going":false,"_tribe_ticket_use_global_stock":"","_tribe_ticket_global_stock_level":"","_global_stock_mode":"","_global_stock_cap":"","_tribe_rsvp_for_event":"","_tribe_ticket_going_count":"","_tribe_ticket_not_going_count":"","_tribe_tickets_list":"[]","_tribe_ticket_has_attendee_info_fields":false,"footnotes":""},"categories":[18],"tags":[],"class_list":["post-27404","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","post_series-ngrx-signal-store-en"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Using Angular&#039;s Resource API with the NGRX Signal Store - ANGULARarchitects<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Using Angular&#039;s Resource API with the NGRX Signal Store - ANGULARarchitects\" \/>\n<meta property=\"og:description\" content=\"This is post 5 of 7 in the series &ldquo;NGRX Signal Store&rdquo; The new NGRX Signal Store for Angular: 3+n Flavors Smarter, Not Harder: Simplifying your Application With NGRX Signal Store and Custom Features NGRX Signal Store Deep Dive: Flexible and Type-Safe Custom Extensions The NGRX Signal Store and Your Architecture Using Angular&#8217;s Resource API [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/\" \/>\n<meta property=\"og:site_name\" content=\"ANGULARarchitects\" \/>\n<meta property=\"article:published_time\" content=\"2024-12-18T15:33:39+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-04T09:24:48+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2024\/12\/Read-NOW.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"628\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Manfred Steyer, GDE\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2024\/12\/Read-NOW.jpg\" \/>\n<meta name=\"twitter:creator\" content=\"@daniel\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Manfred Steyer, GDE\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/\"},\"author\":{\"name\":\"Manfred Steyer, GDE\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951\"},\"headline\":\"Using Angular&#8217;s Resource API with the NGRX Signal Store\",\"datePublished\":\"2024-12-18T15:33:39+00:00\",\"dateModified\":\"2025-06-04T09:24:48+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/\"},\"wordCount\":1353,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2024\/12\/shutterstock_2490358839.jpg\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/\",\"name\":\"Using Angular's Resource API with the NGRX Signal Store - ANGULARarchitects\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2024\/12\/shutterstock_2490358839.jpg\",\"datePublished\":\"2024-12-18T15:33:39+00:00\",\"dateModified\":\"2025-06-04T09:24:48+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/#primaryimage\",\"url\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2024\/12\/shutterstock_2490358839.jpg\",\"contentUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2024\/12\/shutterstock_2490358839.jpg\",\"width\":1024,\"height\":1024},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.angulararchitects.io\/en\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Using Angular&#8217;s Resource API with the NGRX Signal Store\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#website\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/\",\"name\":\"ANGULARarchitects\",\"description\":\"AngularArchitects.io\",\"publisher\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.angulararchitects.io\/en\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\",\"name\":\"ANGULARarchitects\",\"alternateName\":\"SOFTWAREarchitects\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg\",\"contentUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg\",\"width\":644,\"height\":216,\"caption\":\"ANGULARarchitects\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/github.com\/angular-architects\",\"https:\/\/www.linkedin.com\/company\/angular-architects\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951\",\"name\":\"Manfred Steyer, GDE\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/a0b59539674d8b71ea1c1f4764b11244b5f499203f1d11b40f37d8f3f90be033?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/a0b59539674d8b71ea1c1f4764b11244b5f499203f1d11b40f37d8f3f90be033?s=96&d=mm&r=g\",\"caption\":\"Manfred Steyer, GDE\"},\"sameAs\":[\"https:\/\/x.com\/daniel\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Using Angular's Resource API with the NGRX Signal Store - ANGULARarchitects","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/","og_locale":"en_US","og_type":"article","og_title":"Using Angular's Resource API with the NGRX Signal Store - ANGULARarchitects","og_description":"This is post 5 of 7 in the series &ldquo;NGRX Signal Store&rdquo; The new NGRX Signal Store for Angular: 3+n Flavors Smarter, Not Harder: Simplifying your Application With NGRX Signal Store and Custom Features NGRX Signal Store Deep Dive: Flexible and Type-Safe Custom Extensions The NGRX Signal Store and Your Architecture Using Angular&#8217;s Resource API [&hellip;]","og_url":"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/","og_site_name":"ANGULARarchitects","article_published_time":"2024-12-18T15:33:39+00:00","article_modified_time":"2025-06-04T09:24:48+00:00","og_image":[{"width":1200,"height":628,"url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2024\/12\/Read-NOW.jpg","type":"image\/jpeg"}],"author":"Manfred Steyer, GDE","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2024\/12\/Read-NOW.jpg","twitter_creator":"@daniel","twitter_misc":{"Written by":"Manfred Steyer, GDE","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/#article","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/"},"author":{"name":"Manfred Steyer, GDE","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951"},"headline":"Using Angular&#8217;s Resource API with the NGRX Signal Store","datePublished":"2024-12-18T15:33:39+00:00","dateModified":"2025-06-04T09:24:48+00:00","mainEntityOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/"},"wordCount":1353,"commentCount":0,"publisher":{"@id":"https:\/\/www.angulararchitects.io\/en\/#organization"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2024\/12\/shutterstock_2490358839.jpg","inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/","url":"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/","name":"Using Angular's Resource API with the NGRX Signal Store - ANGULARarchitects","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/#primaryimage"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2024\/12\/shutterstock_2490358839.jpg","datePublished":"2024-12-18T15:33:39+00:00","dateModified":"2025-06-04T09:24:48+00:00","breadcrumb":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/#primaryimage","url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2024\/12\/shutterstock_2490358839.jpg","contentUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2024\/12\/shutterstock_2490358839.jpg","width":1024,"height":1024},{"@type":"BreadcrumbList","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/using-the-resource-api-with-the-ngrx-signal-store\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.angulararchitects.io\/en\/"},{"@type":"ListItem","position":2,"name":"Using Angular&#8217;s Resource API with the NGRX Signal Store"}]},{"@type":"WebSite","@id":"https:\/\/www.angulararchitects.io\/en\/#website","url":"https:\/\/www.angulararchitects.io\/en\/","name":"ANGULARarchitects","description":"AngularArchitects.io","publisher":{"@id":"https:\/\/www.angulararchitects.io\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.angulararchitects.io\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.angulararchitects.io\/en\/#organization","name":"ANGULARarchitects","alternateName":"SOFTWAREarchitects","url":"https:\/\/www.angulararchitects.io\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/","url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg","contentUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg","width":644,"height":216,"caption":"ANGULARarchitects"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/github.com\/angular-architects","https:\/\/www.linkedin.com\/company\/angular-architects\/"]},{"@type":"Person","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951","name":"Manfred Steyer, GDE","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/a0b59539674d8b71ea1c1f4764b11244b5f499203f1d11b40f37d8f3f90be033?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/a0b59539674d8b71ea1c1f4764b11244b5f499203f1d11b40f37d8f3f90be033?s=96&d=mm&r=g","caption":"Manfred Steyer, GDE"},"sameAs":["https:\/\/x.com\/daniel"]}]}},"_links":{"self":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/27404","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/users\/9"}],"replies":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/comments?post=27404"}],"version-history":[{"count":9,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/27404\/revisions"}],"predecessor-version":[{"id":30470,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/27404\/revisions\/30470"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media\/27402"}],"wp:attachment":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media?parent=27404"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/categories?post=27404"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/tags?post=27404"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}