JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 5
  • Score
    100M100P100Q45707F
  • License MIT

Convert OpenAPI YAML specs into typed React hooks with caching, polling, and cancellation support. Now with React 19 support!

Package Exports

  • react-api-weaver

Readme

โšก React API Weaver

Convert OpenAPI/Swagger YAML specifications into typed React hooks with caching, polling, and cancellation support.

๐ŸŒŸ Features

  • ๐Ÿ”„ OpenAPI/Swagger Support: Convert YAML specs into TypeScript/JavaScript code
  • ๐ŸŽฃ React Hooks: Method-specific hooks (useGet, usePost, usePut, usePatch, useDelete)
  • ๐Ÿ’พ Smart Caching: Built-in response caching with TTL support
  • ๐Ÿ” Polling: Auto-refresh data at regular intervals
  • ๐Ÿ›‘ Request Cancellation: Abort in-flight requests
  • ๐Ÿ“˜ Full TypeScript Support: Auto-generated types from OpenAPI schemas
  • ๐Ÿš€ Zero Configuration: Works out of the box
  • ๐ŸŽฏ Type-Safe: End-to-end type safety from API to UI
  • โšก Lightweight: Minimal dependencies, tree-shakeable
  • โœจ React 19 Ready: Full support for React 17, 18, and 19 with new hooks
    • Optimistic Updates with useOptimistic (React 19+)
    • Form Actions with useActionState (React 19+)
    • Backward Compatible: Graceful fallback for React 17/18

๐Ÿ“ฆ Installation

npm install react-api-weaver

๐Ÿš€ Quick Start

1. Create an OpenAPI YAML file

Create a api.yaml file with your API specification:

openapi: 3.0.0
info:
  title: My API
  version: 1.0.0

servers:
  - url: https://api.example.com

paths:
  /users:
    get:
      operationId: getUsers
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: integer
                    name:
                      type: string

2. Generate API client code

npx react-api-weaver generate -i api.yaml -o src/generated

This generates TypeScript functions and types:

  • src/generated/api.ts - API functions
  • src/generated/types.ts - TypeScript types/interfaces for requests and responses
  • src/generated/index.ts - Exports for easy importing

3. Use the generated hooks in your React components

import React from 'react';
import { useGet } from 'react-api-weaver';
import { getUsers } from './generated/api';

function UserList() {
  const { data, loading, error, refetch, abort } = useGet(
    () => getUsers(),
    {
      cache: true,
      polling: 30000, // Refresh every 30 seconds
    }
  );

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <button onClick={refetch}>Refresh</button>
      <button onClick={abort}>Cancel</button>
      {data?.map(user => (
        <div key={user.id}>{user.name}</div>
      ))}
    </div>
  );
}

๐Ÿ“– CLI Usage

Generate Command

Generate API client code from OpenAPI YAML:

react-api-weaver generate -i <input.yaml> -o <output-dir> [options]

Options:

  • -i, --input <path>: Path to OpenAPI YAML file (required)
  • -o, --output <path>: Output directory for generated code (required)
  • -f, --format <format>: Output format: ts, js, or both (default: ts)
  • -b, --base-url <url>: Base URL for API requests

Example:

react-api-weaver generate -i api.yaml -o src/generated -f ts -b https://api.example.com

Watch Command

Watch for changes and regenerate automatically:

react-api-weaver watch -i <input.yaml> -o <output-dir> [options]

Example:

react-api-weaver watch -i api.yaml -o src/generated

๐ŸŽฃ Hooks API

Standard Hooks

useGet

Hook for GET requests with caching support.

const { data, loading, error, refetch, abort } = useGet(
  apiFunction,
  options
);

usePost

Hook for POST requests (cache disabled by default).

const { data, loading, error, refetch, abort } = usePost(
  apiFunction,
  options
);

usePut

Hook for PUT requests (cache disabled by default).

const { data, loading, error, refetch, abort } = usePut(
  apiFunction,
  options
);

usePatch

Hook for PATCH requests (cache disabled by default).

const { data, loading, error, refetch, abort } = usePatch(
  apiFunction,
  options
);

useDelete

Hook for DELETE requests (cache disabled by default).

const { data, loading, error, refetch, abort } = useDelete(
  apiFunction,
  options
);

React 19+ Hooks (with React 17/18 Fallback)

useApiOptimistic

Hook for mutations with optimistic updates using React 19's useOptimistic.

const { data, optimisticData, loading, error, mutate, abort } = useApiOptimistic(
  apiFunction,
  {
    optimisticUpdate: (currentData, input) => {
      // Return the optimistic state
      return { ...currentData, ...input };
    },
    onSuccess: (data) => console.log('Success!', data),
  }
);

Specialized Optimistic Hooks:

  • usePostOptimistic - POST with optimistic updates
  • usePutOptimistic - PUT with optimistic updates
  • usePatchOptimistic - PATCH with optimistic updates
  • useDeleteOptimistic - DELETE with optimistic updates

useApiAction

Hook for form-based API interactions using React 19's useActionState.

const { data, error, isPending, action, formAction } = useApiAction(
  apiFunction,
  {
    onSuccess: (data) => console.log('Success!', data),
  }
);

// Use with forms
<form action={formAction}>
  <input name="title" />
  <button type="submit">Submit</button>
</form>

// Or call directly
await action({ title: 'New Todo' });

โš™๏ธ Hook Options

All hooks accept an options object:

interface UseApiOptions<TData> {
  // Enable/disable caching (default: true for GET, false for others)
  cache?: boolean | {
    ttl?: number;  // Time to live in milliseconds
    key?: string;  // Custom cache key
  };

  // Polling interval in milliseconds
  polling?: number;

  // Whether the request should be executed (default: true)
  enabled?: boolean;

  // Success callback
  onSuccess?: (data: TData) => void;

  // Error callback
  onError?: (error: Error) => void;

  // Number of retries or boolean (default: 0)
  retry?: number | boolean;

  // Delay between retries in milliseconds (default: 1000)
  retryDelay?: number;
}

๐ŸŽฏ Return Values

All hooks return an object with:

interface UseApiResult<TData> {
  // Response data
  data: TData | null;

  // Loading state
  loading: boolean;

  // Error object
  error: Error | null;

  // Manual refetch function
  refetch: () => Promise<void>;

  // Abort current request
  abort: () => void;
}

๐Ÿ’ก Examples

Example 1: Basic GET with Caching

import { useGet } from 'react-api-weaver';
import { getTodos } from './generated/api';

function TodoList() {
  const { data, loading } = useGet(
    () => getTodos({ _limit: 10 }),
    { cache: { ttl: 300000 } } // Cache for 5 minutes
  );

  if (loading) return <div>Loading...</div>;

  return (
    <ul>
      {data?.map(todo => <li key={todo.id}>{todo.title}</li>)}
    </ul>
  );
}

Example 2: POST with Success Callback

import { usePost } from 'react-api-weaver';
import { createTodo } from './generated/api';

function CreateTodo() {
  const [title, setTitle] = useState('');

  const { loading, refetch } = usePost(
    () => createTodo({}, { title, userId: 1, completed: false }),
    {
      enabled: false,
      onSuccess: (data) => {
        console.log('Todo created:', data);
        setTitle('');
      },
    }
  );

  const handleSubmit = (e) => {
    e.preventDefault();
    refetch();
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={title}
        onChange={(e) => setTitle(e.target.value)}
      />
      <button disabled={loading}>Create</button>
    </form>
  );
}

Example 3: Polling

import { useGet } from 'react-api-weaver';
import { getTodoById } from './generated/api';

function LiveTodo({ id }) {
  const { data } = useGet(
    () => getTodoById({ id }),
    { polling: 5000 } // Poll every 5 seconds
  );

  return <div>{data?.title}</div>;
}

Example 4: Request Cancellation

import { useGet } from 'react-api-weaver';
import { getUsers } from './generated/api';

function UserList() {
  const { data, loading, abort } = useGet(() => getUsers());

  return (
    <div>
      {loading && <button onClick={abort}>Cancel</button>}
      {data && <div>{data.length} users loaded</div>}
    </div>
  );
}

Example 5: Conditional Requests

import { useGet } from 'react-api-weaver';
import { getUserById } from './generated/api';

function UserProfile({ userId }) {
  const { data } = useGet(
    () => getUserById({ id: userId }),
    { enabled: !!userId } // Only fetch when userId is available
  );

  return <div>{data?.name}</div>;
}

Example 6: Optimistic Updates (React 19+)

import { usePostOptimistic } from 'react-api-weaver';
import { createTodo } from './generated/api';

function OptimisticTodo() {
  const [todos, setTodos] = useState([]);
  
  const { optimisticData, loading, mutate } = usePostOptimistic(
    (input) => createTodo(input),
    {
      optimisticUpdate: (current, input) => ({
        id: Date.now(), // Temporary ID
        ...input,
      }),
      onSuccess: (data) => {
        setTodos(prev => [...prev, data]);
      },
    }
  );

  const handleCreate = () => {
    mutate({ title: 'New Todo', userId: 1, completed: false });
  };

  return (
    <div>
      <button onClick={handleCreate} disabled={loading}>
        Add Todo
      </button>
      {optimisticData && (
        <div style={{ opacity: loading ? 0.5 : 1 }}>
          โšก {optimisticData.title} (optimistic)
        </div>
      )}
      {todos.map(todo => (
        <div key={todo.id}>{todo.title}</div>
      ))}
    </div>
  );
}

Example 7: Form Actions (React 19+)

import { useApiAction } from 'react-api-weaver';
import { createTodo } from './generated/api';

function TodoForm() {
  const { data, error, isPending, formAction } = useApiAction(
    (input) => createTodo({
      userId: 1,
      title: input.title,
      completed: input.completed === 'true',
    })
  );

  return (
    <form action={formAction}>
      <input name="title" placeholder="Todo title" required />
      <select name="completed">
        <option value="false">Not Done</option>
        <option value="true">Done</option>
      </select>
      <button type="submit" disabled={isPending}>
        {isPending ? 'Creating...' : 'Create Todo'}
      </button>
      {error && <div>Error: {error.message}</div>}
      {data && <div>Created: {data.title}</div>}
    </form>
  );
}

๐Ÿ”ง Configuration

Custom Request Configuration

The generated API functions accept a RequestConfig parameter:

interface RequestConfig {
  headers?: Record<string, string>;
  baseURL?: string;
  timeout?: number;
  signal?: AbortSignal;
}

Example:

const { data } = useGet(
  () => getUsers({}, {
    headers: { 'Authorization': 'Bearer token' },
    timeout: 5000,
  })
);

Setting Default Base URL

You can set a base URL in three ways:

  1. In the OpenAPI YAML (servers section)
  2. Via CLI: react-api-weaver generate -i api.yaml -o src/generated -b https://api.example.com
  3. At runtime: Pass baseURL in the request config

๐Ÿ“ Project Structure

your-project/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ generated/          # Generated API code
โ”‚   โ”‚   โ”œโ”€โ”€ api.ts          # Generated API functions
โ”‚   โ”‚   โ”œโ”€โ”€ types.ts        # TypeScript types/interfaces
โ”‚   โ”‚   โ””โ”€โ”€ index.ts        # Exports (functions + types)
โ”‚   โ””โ”€โ”€ components/
โ”‚       โ””โ”€โ”€ UserList.tsx    # Your components using hooks
โ”œโ”€โ”€ api.yaml                # OpenAPI specification
โ””โ”€โ”€ package.json

๐Ÿ“˜ Type Exports

All TypeScript types are exported from the generated types.ts file. You can import types separately from functions:

// Import functions
import { getUsers, createUser } from './generated/api';

// Import types separately
import type { GetUsersResponse, CreateUserBody, CreateUserResponse } from './generated/types';

// Or import everything from index
import { getUsers, type GetUsersResponse } from './generated';

Available Types:

  • {OperationName}Params - Request parameters (for GET, DELETE, etc.)
  • {OperationName}Body - Request body (for POST, PUT, PATCH)
  • {OperationName}Response - Response data type

Example:

import { getTodoById } from './generated/api';
import type { GetTodoByIdParams, GetTodoByIdResponse } from './generated/types';

function TodoComponent({ todoId }: { todoId: number }) {
  const params: GetTodoByIdParams = { id: todoId };
  const { data } = useGet<GetTodoByIdResponse>(
    () => getTodoById(params)
  );
  
  return <div>{data?.title}</div>;
}

๐Ÿ› ๏ธ Development Workflow

Option 1: Manual Generation

{
  "scripts": {
    "generate": "react-api-weaver generate -i api.yaml -o src/generated"
  }
}

Run npm run generate when you update your API spec.

Option 2: Pre-development Generation

{
  "scripts": {
    "predev": "react-api-weaver generate -i api.yaml -o src/generated",
    "dev": "vite"
  }
}

Automatically generates code before starting the dev server.

Option 3: Watch Mode (Separate Terminal)

react-api-weaver watch -i api.yaml -o src/generated

Automatically regenerates code when the YAML file changes.

For local development and testing:

# In react-api-weaver directory
npm run build
npm link

# In your project directory
npm link react-api-weaver

๐Ÿค Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

๐Ÿ“„ License

MIT

๐Ÿ™ Acknowledgments

โ˜• Support

If you find this project helpful, consider supporting me by buying me a coffee!

Buy Me A Coffee


๐ŸŽ‰ React 19 Features

React API Weaver now fully supports React 19 while maintaining backward compatibility with React 17 and 18.

What's New in React 19 Support

1. Optimistic Updates

Use useOptimistic (React 19) for instant UI feedback before server responses:

import { usePostOptimistic } from 'react-api-weaver';

const { optimisticData, mutate } = usePostOptimistic(
  createTodo,
  {
    optimisticUpdate: (current, input) => ({
      id: Date.now(),
      ...input,
    }),
  }
);

Benefits:

  • โšก Instant UI updates
  • ๐Ÿ”„ Automatic rollback on errors
  • ๐ŸŽฏ Type-safe optimistic state

2. Form Actions

Use useActionState (React 19) for progressive enhancement:

import { useApiAction } from 'react-api-weaver';

const { formAction, isPending } = useApiAction(createTodo);

<form action={formAction}>
  <input name="title" />
  <button type="submit" disabled={isPending}>Submit</button>
</form>

Benefits:

  • ๐Ÿ“ Works with native form elements
  • ๐Ÿš€ Progressive enhancement
  • ๐ŸŽฏ Built-in pending states

3. Version Detection

Check React version at runtime:

import { isReact19OrLater, getReactMajorVersion } from 'react-api-weaver';

if (isReact19OrLater()) {
  console.log('React 19 features available!');
}

Backward Compatibility

All React 19 features gracefully degrade on React 17/18:

Feature React 19 React 17/18 Fallback
useApiOptimistic Uses native useOptimistic Manual state management
useApiAction Uses native useActionState useTransition + state
Optimistic hooks Native rollback Manual error handling

Migration Guide

From React 18 to React 19

Step 1: Update Dependencies

npm install react@19 react-dom@19
npm install react-api-weaver@latest

Step 2: Use New Hooks (Optional)

Replace standard mutation hooks with optimistic variants:

// Before (React 18)
const { data, loading, refetch } = usePost(createTodo, {
  enabled: false,
  onSuccess: (data) => {
    setItems(prev => [...prev, data]);
  }
});

// After (React 19)
const { optimisticData, loading, mutate } = usePostOptimistic(createTodo, {
  optimisticUpdate: (current, input) => ({
    id: Date.now(),
    ...input,
  }),
  onSuccess: (data) => {
    setItems(prev => [...prev, data]);
  }
});

Step 3: Adopt Form Actions (Optional)

// Before (React 18)
const handleSubmit = async (e) => {
  e.preventDefault();
  const formData = new FormData(e.target);
  await createTodo(Object.fromEntries(formData));
};

// After (React 19)
const { formAction } = useApiAction(createTodo);

<form action={formAction}>
  {/* form fields */}
</form>

Best Practices

When to Use Optimistic Updates

โœ… Good use cases:

  • Creating new items in a list
  • Toggling boolean states (like/unlike)
  • Updating text fields
  • Deleting items with visual feedback

โŒ Avoid for:

  • Complex server-side validation
  • Operations with side effects
  • Critical financial transactions
  • When server response differs significantly from input

When to Use Form Actions

โœ… Good use cases:

  • Traditional form submissions
  • Server-side validation
  • Progressive enhancement
  • Multi-step forms

โŒ Avoid for:

  • Real-time validation
  • Complex client-side logic
  • Non-form interactions

๐Ÿ“ Next Steps (Optional Enhancements)

Potential Future Features

  • Optimistic updates (React 19)
  • Form actions (React 19)
  • Automated testing (Jest + React Testing Library)
  • React Query integration
  • Middleware support (interceptors)
  • WebSocket support
  • GraphQL support
  • Zod schema validation
  • Devtools integration

Documentation Improvements

  • Video tutorial
  • Interactive playground
  • More examples (auth, pagination, etc.)
  • API reference site

Made with โค๏ธ by the React API Weaver team