Skip to content

Instantly share code, notes, and snippets.

@meetdave3
Created April 29, 2025 21:35
Show Gist options
  • Save meetdave3/53eb7ca1a835173c3aacde43a9784b04 to your computer and use it in GitHub Desktop.
Save meetdave3/53eb7ca1a835173c3aacde43a9784b04 to your computer and use it in GitHub Desktop.

Your goal is to implement new API hooks and modify existing ones while following these established patterns and best practices. Use React Query (TanStack Query), Zod for schema validation.

Follow the same practices for POST request as well.

Technical Stack

  • TypeScript
  • React Query (TanStack Query)
  • Zod for schema validation

Core Guidelines

  1. API Hook Structure:

    • Each hook should be prefixed with use
    • Use TypeScript generics for response types
    • Include Zod schema validation for API responses
    • Implement proper React Query configuration
  2. Standard Parameters:

    interface HookParams<T> {
      params: T;
      enabled?: boolean;
    }
  3. Query Configuration:

    • Always include proper queryKey arrays with params
    • Set appropriate staleTime (default: 5 minutes)
    • Set appropriate gcTime (default: 10 minutes)
    • Include enabled flag for conditional fetching
  4. Type Safety and Schema Validation:

    • Define Zod schemas as the single source of truth
    • Make all schema fields optional for frontend resilience
    • Infer TypeScript types from Zod schemas using z.infer
    • Export both schemas and inferred types for consumer usage

Example Type Implementation:

// Zod schemas as source of truth
export const responseSchema = z.object({
  id: z.string().optional(),
  name: z.string().optional(),
  data: z.record(z.unknown()).optional(),
});

// Inferred types from schemas
export type Response = z.infer<typeof responseSchema>;

Example Hook Implementation:

import { useApi } from "~/api/fetch";
// other imports

export function useApiEndpoint({
  params,
  enabled = true,
}: {
  params: RequestType;
  enabled?: boolean;
}) {
  const { api } = useApi();

  return useQuery({
    queryKey: ['endpointName', params],
    queryFn: async () => {
      return api<Response>({
        path: '/insert-service-endpoint',
        method: 'POST',
        body: params,
        schema: responseSchema,
      });
    },
    enabled,
    staleTime: 5 * 60 * 1000,
    gcTime: 10 * 60 * 1000,
  });
}

Best Practices

  1. Schema and Type Organization:

    • Keep schemas and types in a dedicated types.ts file
    • Use JSDoc comments to document schema structure
    • Make all response fields optional for resilience
    • Group related schemas and types together
  2. Documentation:

    • Document hooks with JSDoc comments explaining:
      • Purpose of the hook
      • Parameters
      • Return value
      • Any special considerations
    • Include examples of usage where helpful
  3. Endpoint Constants:

    • Define API endpoints as constants at the top of the file
    • Use descriptive names that match the service/method
  4. Error Handling:

    • Let React Query handle retry logic
    • Use type-safe error responses
    • Consider implementing error boundaries for API failures
  5. Caching Strategy:

    • Configure appropriate staleTime based on data freshness requirements
    • Set gcTime to prevent memory leaks
    • Use invalidation queries when needed
  6. Frontend Resilience:

    • Make all schema fields optional
    • Provide fallback values for missing data
    • Handle loading and error states gracefully
    • Use type guards for runtime safety

File Structure:

/api
  /service-name
    /index.ts        // Exports
    /types.ts        // Schemas & Types
    /useEndpoint.ts  // Hook Implementation

Follow these guidelines when implementing new API integrations or modifying existing ones to maintain consistency, type safety, and resilience across the application.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment