Skip to main content
createApi is the core function of ngrx-rtk-query that generates an API slice with Angular-compatible hooks for queries and mutations. It wraps RTK Query’s buildCreateApi with Angular-specific hooks module.

Function Signature

function createApi<
  Definitions extends EndpointDefinitions
>(
  options: CreateApiOptions<Definitions>
): Api<Definitions> & { initApiStore: (setupFn: () => AngularHooksModuleOptions) => void }

Parameters

options
CreateApiOptions
required
Configuration object for the API

Return Value

Api
object
An API object with generated hooks and utilities

Usage Examples

Basic API Definition

import { createApi, fetchBaseQuery } from 'ngrx-rtk-query';

interface Post {
  id: number;
  title: string;
  content: string;
}

export const postsApi = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: 'https://api.example.com' }),
  tagTypes: ['Posts'],
  endpoints: (build) => ({
    getPosts: build.query<Post[], void>({
      query: () => ({ url: '/posts' }),
      providesTags: (result) =>
        result
          ? [...result.map(({ id }) => ({ type: 'Posts', id })), { type: 'Posts', id: 'LIST' }]
          : [{ type: 'Posts', id: 'LIST' }],
    }),
    getPost: build.query<Post, number>({
      query: (id) => `/posts/${id}`,
      providesTags: (result, error, id) => [{ type: 'Posts', id }],
    }),
    addPost: build.mutation<Post, Partial<Post>>({
      query: (body) => ({
        url: '/posts',
        method: 'POST',
        body,
      }),
      invalidatesTags: [{ type: 'Posts', id: 'LIST' }],
    }),
    updatePost: build.mutation<Post, Partial<Post>>({
      query: (data) => {
        const { id, ...body } = data;
        return {
          url: `/posts/${id}`,
          method: 'PUT',
          body,
        };
      },
      invalidatesTags: (result, error, { id }) => [{ type: 'Posts', id }],
    }),
    deletePost: build.mutation<{ success: boolean; id: number }, number>({
      query: (id) => ({
        url: `/posts/${id}`,
        method: 'DELETE',
      }),
      invalidatesTags: [{ type: 'Posts', id: 'LIST' }],
    }),
  }),
});

// Export generated hooks
export const {
  useGetPostsQuery,
  useGetPostQuery,
  useAddPostMutation,
  useUpdatePostMutation,
  useDeletePostMutation,
} = postsApi;

Using Generated Hooks in Components

import { Component, ChangeDetectionStrategy } from '@angular/core';
import { useGetPostsQuery, useAddPostMutation } from './api';

@Component({
  selector: 'app-posts-list',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    @if (postsQuery.isLoading()) {
      <p>Loading posts...</p>
    }
    @if (postsQuery.error(); as error) {
      <p>Error: {{ error.message }}</p>
    }
    @if (postsQuery.data(); as posts) {
      <ul>
        @for (post of posts; track post.id) {
          <li>{{ post.title }}</li>
        }
      </ul>
    }
    <button 
      [disabled]="addPost.isLoading()" 
      (click)="createNewPost()">
      Add Post
    </button>
  `,
})
export class PostsListComponent {
  postsQuery = useGetPostsQuery();
  addPost = useAddPostMutation();

  createNewPost() {
    this.addPost({ title: 'New Post', content: 'Hello World' })
      .unwrap()
      .then(() => console.log('Post created!'))
      .catch((error) => console.error('Failed to create post:', error));
  }
}

With Query Options

import { Component, signal } from '@angular/core';
import { skipToken } from '@reduxjs/toolkit/query';
import { useGetPostQuery } from './api';

@Component({
  selector: 'app-post-details',
  standalone: true,
  template: `
    @if (postQuery.data(); as post) {
      <h1>{{ post.title }}</h1>
      <p>{{ post.content }}</p>
    }
  `,
})
export class PostDetailsComponent {
  postId = signal<number | null>(null);

  // Skip query if no ID is set
  postQuery = useGetPostQuery(
    () => this.postId() ?? skipToken,
    {
      pollingInterval: 5000, // Poll every 5 seconds
      refetchOnFocus: true,
    }
  );
}

Integration with Store

The created API must be provided to Angular’s dependency injection system using either provideStoreApi (with NgRx Store) or provideNoopStoreApi (standalone):

With NgRx Store

import { ApplicationConfig } from '@angular/core';
import { provideStore } from '@ngrx/store';
import { provideStoreApi } from 'ngrx-rtk-query';
import { postsApi } from './posts/api';

export const appConfig: ApplicationConfig = {
  providers: [
    provideStore(),
    provideStoreApi(postsApi),
  ],
};

Without NgRx Store

import { ApplicationConfig } from '@angular/core';
import { provideNoopStoreApi } from 'ngrx-rtk-query/noop-store';
import { postsApi } from './posts/api';

export const appConfig: ApplicationConfig = {
  providers: [
    provideNoopStoreApi(postsApi),
  ],
};

Implementation Details

The createApi function:
  1. Sets up dispatch mechanism: Creates a dispatch function that handles both regular actions and thunks, with access to Angular’s injector for dependency injection
  2. Configures state selectors: Provides getState and useSelector functions that integrate with the store
  3. Builds the API: Uses RTK Query’s buildCreateApi with the core module and Angular hooks module
  4. Generates hooks: Automatically creates useQuery, useLazyQuery, useMutation, and useInfiniteQuery hooks for each endpoint
  5. Initializes middleware: Sets up the RTK Query middleware with the configured dispatch and getState functions

Source Reference

Source: packages/ngrx-rtk-query/core/src/create-api.ts:19

See Also

Build docs developers (and LLMs) love