Building a Robust API Layer – `api-def` Package Integration with React (NextJs) app



This content originally appeared on DEV Community and was authored by Santhanam Elumalai

Welcome back! In this part, we’ll demonstrate how to integrate the api-def package with a Next.js application for client-side and server-side API fetching using Tanstack Query.

Recap:

  • We explored the concept and implementation of the api-def package.

Integration with Tanstack Query:

  1. Configure Tanstack Client:
    • Create a Providers component to manage the QueryClient instance.
    • Use isServer from @tanstack/react-query to create separate clients for server and client.
  import { QueryClient, QueryClientProvider, isServer } from "@tanstack/react-query";

  function makeQueryClient() {
      return new QueryClient({
          defaultOptions: {
              queries: {
                  staleTime: 60 * 1000, // Cache timeout in milliseconds
              },
          },
      });
  }

  let browserQueryClient: QueryClient | undefined = undefined;

  function getQueryClient() {
      if (isServer) {
          return makeQueryClient();
      } else {
          if (!browserQueryClient) {
              browserQueryClient = makeQueryClient();
          }
          return browserQueryClient;
      }
  }

  export function Providers({ children }: { children: React.Node }) {
      const queryClient = getQueryClient();
      return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
  }
  1. Provider Placement:
    • Wrap your application with the Providers component at the root level (e.g., in layout.tsx) to make the QueryClient context globally accessible.
  import { Providers } from "./providers";

  export default function RootLayout({ children }: { children: React.Node }) {
      return (
          <html lang="en">
              <body>
                  <Providers>{children}</Providers>
              </body>
          </html>
      );
  }
  1. Client-Side Fetching:
    • Create a component (e.g., Users component) that utilizes the useQuery hook from Tanstack Query.
    • Use the GetUserKeys function from api-def to define the query key for caching and invalidation.
    • Use the ApiClient from api-def within the queryFn to fetch data from the API.
  import { GetUserKeys, ApiClient } from "@repo/api-definitions";
  import { useQuery } from "@tanstack/react-query";

  export function Users() {
      const { data } = useQuery({
          queryKey: GetUserKeys.getUsers({}),
          queryFn: async ({ queryKey }) => {
              const queries = queryKey[0]?.requestBody;
              return ApiClient.getUsers(queries || {});
          },
      });

      return <>{JSON.stringify(data)}</>;
  }
  1. Server-Side Prefetching:
    • Within a server component (e.g., in page.tsx), prefetch the data using queryClient.prefetchQuery before rendering the component.
    • Use the same GetUserKeys and ApiClient from api-def within the queryFn for consistency.
    • Wrap the component with a HydrationBoundary from Tanstack Query to hydrate the prefetched data on the client.
  import { dehydrate, HydrationBoundary, QueryClient } from "@tanstack/react-query";
  import { GetUserKeys, ApiClient } from "@repo/api-definitions";
  import { Users } from "@app/user/users";

  export default async function PostsPage() {
      const queryClient = new QueryClient();
      await queryClient.prefetchQuery({
          queryKey: GetUserKeys.getUsers({}),
          queryFn: ({ queryKey: [requestBody] }) => {
              return ApiClient.getUsers(requestBody?.requestBody || {});
          },
      });
      return (
          <HydrationBoundary state={dehydrate(queryClient)}>
              <Users />
          </HydrationBoundary>
      );
  }

Benefits:

  • Type safety: Zod ensures type safety throughout the API interactions.
  • Centralized definitions: api-def offers a single source for API definitions and endpoints.
  • Efficient caching: Tanstack Query manages caching and invalidation for optimized performance.

Next Steps:

In the upcoming post, we’ll delve into the integration of another powerful tool: React Hook Form. This library will help us streamline form handling, validation, and submission processes within our React applications.

Stay tuned!

Github PR Location

Footnote: This implementation is inspired by the Tanstack Query documentation on Advanced Server-Side Rendering: Advanced Server Rendering


This content originally appeared on DEV Community and was authored by Santhanam Elumalai