npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

swd-axios-query

v3.1.7

Published

A React hooks library for easy API requests using Axios and React Query

Readme

SWD Axios Query

npm version license

A lightweight library that simplifies making API requests in React applications. Combines the power of Axios and React Query for seamless API interactions, caching, and state updates.


Table of Contents


Features

| Feature | Description | |-----------------------------------------|------------------------------------------------------------------| | Easy-to-use hooks | For GET, POST, PUT, DELETE requests | | Global Axios/React Query config | Set base URL, headers, and query options | | Query provider | Manages React Query client context | | Custom headers/base URL | Add/override headers and base URL globally | | React Query Devtools support | Enable devtools for debugging | | NEW: Axios interceptors | Add/remove request/response interceptors globally | | NEW: Global loading/error context | Track all API loading/error states with a single provider/hook |


Installation

npm install swd-axios-query
# or
yarn add swd-axios-query

Quick Start

1. Configure the Package

import { configureSWDQuery } from 'swd-axios-query';

configureSWDQuery({
  baseURL: 'https://api.example.com',
  headers: { Authorization: 'Bearer your_token_here' },
  defaultOptions: { retry: 1, refetchOnMount: true },
});

2. Wrap Your App

import { SWDQueryProvider } from 'swd-axios-query';

<SWDQueryProvider enableDevTools={true}>
  <App />
</SWDQueryProvider>

3. Use Hooks in Components

import { useGet } from 'swd-axios-query';
import { useEffect } from 'react';

function Todos() {
  const { data, error, isLoading, isSuccess, isError } = useGet(['todos'], '/todos');
  
  // Handle success/error states using useEffect (TanStack Query v5 pattern)
  useEffect(() => {
    if (isSuccess) {
      console.log('Data loaded successfully:', data);
    }
  }, [isSuccess, data]);

  useEffect(() => {
    if (isError) {
      console.error('Error loading data:', error);
    }
  }, [isError, error]);

  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;
  return <ul>{data?.map(todo => <li key={todo.id}>{todo.title}</li>)}</ul>;
}

Full Example

import React from 'react';
import ReactDOM from 'react-dom';
import {
  SWDQueryProvider,
  SWDGlobalStatusProvider,
  configureSWDQuery,
  addRequestInterceptor,
  addResponseInterceptor,
  useGlobalStatus,
  useGet
} from 'swd-axios-query';

// Configure once at app startup
configureSWDQuery({ baseURL: 'https://api.example.com' });

// Optional: Add interceptors
addRequestInterceptor(config => {
  config.headers.Authorization = 'Bearer ' + localStorage.getItem('token');
  return config;
});
addResponseInterceptor(
  response => response,
  error => {
    if (error.response?.status === 401) {
      // Handle unauthorized globally
    }
    return Promise.reject(error);
  }
);

function GlobalSpinner() {
  const { isLoading } = useGlobalStatus();
  return isLoading ? <div className="spinner">Loading...</div> : null;
}

function Todos() {
  const { data, isLoading, error, isSuccess, isError } = useGet(['todos'], '/todos');
  
  // Handle success/error states using useEffect (TanStack Query v5 pattern)
  useEffect(() => {
    if (isSuccess) {
      console.log('Todos loaded successfully:', data);
    }
  }, [isSuccess, data]);

  useEffect(() => {
    if (isError) {
      console.error('Error loading todos:', error);
    }
  }, [isError, error]);

  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;
  return <ul>{data?.map(todo => <li key={todo.id}>{todo.title}</li>)}</ul>;
}

ReactDOM.render(
  <SWDQueryProvider>
    <SWDGlobalStatusProvider>
      <GlobalSpinner />
      <Todos />
    </SWDGlobalStatusProvider>
  </SWDQueryProvider>,
  document.getElementById('root')
);

Mutation Examples

usePost - Creating Data

import { usePost } from 'swd-axios-query';
import { useEffect } from 'react';

function CreateUser() {
  const { mutate, isLoading, error, isSuccess, data } = usePost(
    ['users'], // Query key for cache invalidation
    '/api/users', // API endpoint
    {
      onSuccess: (data) => {
        console.log('User created successfully:', data);
        // Optional: Show success message
      },
      onError: (error) => {
        console.error('Failed to create user:', error);
        // Optional: Show error message
      }
    }
  );

  // Handle success/error states using useEffect (TanStack Query v5 pattern)
  useEffect(() => {
    if (isSuccess) {
      console.log('User created:', data);
      // Optional: Redirect or show success message
    }
  }, [isSuccess, data]);

  useEffect(() => {
    if (error) {
      console.error('Creation failed:', error);
      // Optional: Show error message
    }
  }, [error]);

  const handleSubmit = (formData) => {
    // Direct data passing - no need to wrap in { data: ... }
    mutate({
      name: formData.name,
      email: formData.email,
      age: formData.age
    });
  };

  return (
    <form onSubmit={(e) => {
      e.preventDefault();
      const formData = new FormData(e.target);
      handleSubmit({
        name: formData.get('name'),
        email: formData.get('email'),
        age: parseInt(formData.get('age'))
      });
    }}>
      <input name="name" placeholder="Name" required />
      <input name="email" type="email" placeholder="Email" required />
      <input name="age" type="number" placeholder="Age" required />
      <button type="submit" disabled={isLoading}>
        {isLoading ? 'Creating...' : 'Create User'}
      </button>
      {error && <p style={{color: 'red'}}>Error: {error.message}</p>}
    </form>
  );
}

usePut - Updating Data

import { usePut } from 'swd-axios-query';
import { useEffect } from 'react';

function EditUser({ userId, initialData }) {
  const { mutate, isLoading, error, isSuccess, data } = usePut(
    ['users', userId], // Query key for cache invalidation
    `/api/users/${userId}`, // API endpoint with ID
    {
      onSuccess: (data) => {
        console.log('User updated successfully:', data);
      }
    }
  );

  // Handle success/error states
  useEffect(() => {
    if (isSuccess) {
      console.log('User updated:', data);
      // Optional: Show success message or redirect
    }
  }, [isSuccess, data]);

  const handleUpdate = (updatedData) => {
    // Direct data passing
    mutate({
      ...initialData,
      ...updatedData,
      updatedAt: new Date().toISOString()
    });
  };

  return (
    <form onSubmit={(e) => {
      e.preventDefault();
      const formData = new FormData(e.target);
      handleUpdate({
        name: formData.get('name'),
        email: formData.get('email'),
        age: parseInt(formData.get('age'))
      });
    }}>
      <input 
        name="name" 
        defaultValue={initialData.name} 
        placeholder="Name" 
        required 
      />
      <input 
        name="email" 
        type="email" 
        defaultValue={initialData.email} 
        placeholder="Email" 
        required 
      />
      <input 
        name="age" 
        type="number" 
        defaultValue={initialData.age} 
        placeholder="Age" 
        required 
      />
      <button type="submit" disabled={isLoading}>
        {isLoading ? 'Updating...' : 'Update User'}
      </button>
      {error && <p style={{color: 'red'}}>Error: {error.message}</p>}
    </form>
  );
}

useDelete - Deleting Data

import { useDelete } from 'swd-axios-query';
import { useEffect } from 'react';

function DeleteUser({ userId, onDeleted }) {
  const { mutate, isLoading, error, isSuccess } = useDelete(
    ['users', userId], // Query key for cache invalidation
    `/api/users/${userId}`, // API endpoint with ID
    {
      onSuccess: () => {
        console.log('User deleted successfully');
        // Optional: Call callback or show success message
        if (onDeleted) onDeleted();
      }
    }
  );

  // Handle success/error states
  useEffect(() => {
    if (isSuccess) {
      console.log('User deleted successfully');
      // Optional: Show success message or redirect
    }
  }, [isSuccess]);

  const handleDelete = () => {
    if (window.confirm('Are you sure you want to delete this user?')) {
      // Simple delete without payload
      mutate();
    }
  };

  const handleDeleteWithReason = (reason) => {
    if (window.confirm('Are you sure you want to delete this user?')) {
      // Delete with optional payload
      mutate({
        reason: reason,
        deletedBy: 'current_user',
        deletedAt: new Date().toISOString()
      });
    }
  };

  return (
    <div>
      <button 
        onClick={handleDelete} 
        disabled={isLoading}
        style={{backgroundColor: 'red', color: 'white'}}
      >
        {isLoading ? 'Deleting...' : 'Delete User'}
      </button>
      
      <button 
        onClick={() => handleDeleteWithReason('User requested deletion')} 
        disabled={isLoading}
        style={{backgroundColor: 'darkred', color: 'white', marginLeft: '10px'}}
      >
        {isLoading ? 'Deleting...' : 'Delete with Reason'}
      </button>
      
      {error && <p style={{color: 'red'}}>Error: {error.message}</p>}
    </div>
  );
}

useDelete - Bulk Delete with Payload

import { useDelete } from 'swd-axios-query';

function BulkDeleteUsers({ selectedUserIds }) {
  const { mutate, isLoading, error, isSuccess } = useDelete(
    ['users'], // Query key for cache invalidation
    '/api/users/bulk-delete', // API endpoint for bulk operations
    {
      onSuccess: (data) => {
        console.log('Bulk delete completed:', data);
        // Show success message
      }
    }
  );

  const handleBulkDelete = () => {
    if (window.confirm(`Delete ${selectedUserIds.length} users?`)) {
      // Delete with payload containing IDs and metadata
      mutate({
        userIds: selectedUserIds,
        reason: 'Bulk cleanup',
        deletedBy: 'admin',
        deletedAt: new Date().toISOString(),
        notifyUsers: true
      });
    }
  };

  return (
    <div>
      <button 
        onClick={handleBulkDelete} 
        disabled={isLoading || selectedUserIds.length === 0}
        style={{backgroundColor: 'red', color: 'white'}}
      >
        {isLoading ? 'Deleting...' : `Delete ${selectedUserIds.length} Users`}
      </button>
      {error && <p style={{color: 'red'}}>Error: {error.message}</p>}
      {isSuccess && <p style={{color: 'green'}}>Users deleted successfully!</p>}
    </div>
  );
}

Advanced Mutation Example with Custom Headers

import { usePost, setContentTypeHeaders } from 'swd-axios-query';

function FileUpload() {
  const { mutate, isLoading, error, isSuccess } = usePost(
    ['files'],
    '/api/upload',
    {
      // Custom axios options for this specific request
      axiosOptions: {
        headers: {
          'Content-Type': 'multipart/form-data'
        },
        onUploadProgress: (progressEvent) => {
          const percentCompleted = Math.round(
            (progressEvent.loaded * 100) / progressEvent.total
          );
          console.log(`Upload Progress: ${percentCompleted}%`);
        }
      }
    }
  );

  const handleFileUpload = (file) => {
    const formData = new FormData();
    formData.append('file', file);
    formData.append('description', 'Uploaded file');

    // Direct data passing
    mutate(formData);
  };

  return (
    <div>
      <input 
        type="file" 
        onChange={(e) => {
          const file = e.target.files[0];
          if (file) handleFileUpload(file);
        }}
        disabled={isLoading}
      />
      {isLoading && <p>Uploading...</p>}
      {isSuccess && <p style={{color: 'green'}}>File uploaded successfully!</p>}
      {error && <p style={{color: 'red'}}>Upload failed: {error.message}</p>}
    </div>
  );
}

Mutation with Optimistic Updates

import { usePut, useQueryClient } from 'swd-axios-query';

function ToggleTodo({ todo }) {
  const queryClient = useQueryClient();
  
  const { mutate, isLoading } = usePut(
    ['todos', todo.id],
    `/api/todos/${todo.id}`,
    {
      // Optimistic update
      onMutate: async (newData) => {
        // Cancel outgoing refetches
        await queryClient.cancelQueries({ queryKey: ['todos', todo.id] });
        
        // Snapshot previous value
        const previousTodo = queryClient.getQueryData(['todos', todo.id]);
        
        // Optimistically update
        queryClient.setQueryData(['todos', todo.id], {
          ...previousTodo,
          ...newData
        });
        
        return { previousTodo };
      },
      onError: (err, newData, context) => {
        // Rollback on error
        queryClient.setQueryData(['todos', todo.id], context.previousTodo);
      },
      onSettled: () => {
        // Refetch after error or success
        queryClient.invalidateQueries({ queryKey: ['todos', todo.id] });
      }
    }
  );

  const handleToggle = () => {
    mutate({
      completed: !todo.completed,
      updatedAt: new Date().toISOString()
    });
  };

  return (
    <button 
      onClick={handleToggle} 
      disabled={isLoading}
      style={{
        textDecoration: todo.completed ? 'line-through' : 'none',
        opacity: isLoading ? 0.5 : 1
      }}
    >
      {todo.title}
    </button>
  );
}

Core API Reference

Configuration Functions

configureSWDQuery(config)

Configures the library with custom settings.

  • Parameters:
    • config (object): { baseURL, headers, defaultOptions, timeout }
  • Returns: void

addHeaders(headers, merge)

Adds additional headers dynamically.

  • Parameters:
    • headers (object): Headers to add
    • merge (boolean, optional): Whether to merge with existing headers (default: true)
  • Returns: void

setContentTypeHeaders(contentType, additionalHeaders)

Sets default headers for specific content types.

  • Parameters:
    • contentType (string): Content type (e.g., 'application/json', 'multipart/form-data')
    • additionalHeaders (object, optional): Additional headers to set
  • Returns: void

removeHeaders(headerKeys)

Removes specific headers.

  • Parameters:
    • headerKeys (string|Array): Header key(s) to remove
  • Returns: void

getHeaders()

Gets current headers.

  • Returns: Object - Current headers object

axiosInstance

Direct access to the configured Axios instance for custom requests.

  • Type: Axios instance
  • Usage: For requests outside of React Query hooks

resetToDefaultHeaders()

Resets headers to default values.

  • Returns: void
  • Default Headers: Content-Type: application/json, Accept: application/json

SWDQueryProvider

Wrap your app to provide React Query context.

  • Props:
    • children (ReactNode): The application to wrap.
    • queryClient (QueryClient, optional): Custom React Query client.
    • enableDevTools (boolean, optional): Enable React Query Devtools.

Data Hooks

  • useGet(queryKey, queryUrl, options)
  • usePost(queryKey, queryUrl, options)
  • usePut(queryKey, queryUrl, options)
  • useDelete(queryKey, queryUrl, options)
  • useSuspenseGet(queryKey, queryUrl, options)

Parameters:

  • queryKey (array): Unique key for the query/mutation.
  • queryUrl (string): API endpoint.
  • options (object, optional): React Query options.

Returns:

  • For queries: { data, error, isLoading, isSuccess, isError, ... }
  • For mutations: { mutate, mutateAsync, isLoading, error, ... }

Note: This library follows official TanStack Query v5 patterns. Three approaches are supported:

Approach 1: useEffect with Query States (Recommended)

const { data, isSuccess, isError, error } = useGet(['key'], '/api');

useEffect(() => {
  if (isSuccess) {
    console.log('Success:', data);
  }
}, [isSuccess, data]);

useEffect(() => {
  if (isError) {
    console.error('Error:', error);
  }
}, [isError, error]);

Approach 2: Global Callbacks via QueryClient

// Set up in your app initialization
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      onSuccess: (data, query) => {
        if (query.meta?.onSuccess) {
          query.meta.onSuccess(data);
        }
      },
    },
  },
});

Approach 3: meta Option with Global Callbacks

const { data } = useGet(['key'], '/api', {
  meta: {
    onSuccess: (data) => console.log('Success:', data),
    onError: (error) => console.error('Error:', error),
  }
});

Advanced Usage Examples

Header Management

Default Headers

The library comes with sensible defaults:

  • Content-Type: application/json
  • Accept: application/json

These defaults are automatically applied when you import the library. You can override them using the configuration functions.

Basic Header Configuration

import { configureSWDQuery, addHeaders } from 'swd-axios-query';

// Initial configuration
configureSWDQuery({
  baseURL: 'https://api.example.com',
  headers: {
    'Authorization': 'Bearer your-token',
    'Content-Type': 'application/json'
  }
});

// Add additional headers dynamically
addHeaders({
  'X-Custom-Header': 'custom-value',
  'Accept': 'application/json'
});

Content Type Management

import { setContentTypeHeaders, removeHeaders } from 'swd-axios-query';

// Set headers for file uploads
setContentTypeHeaders('multipart/form-data', {
  'X-Upload-Type': 'file'
});

// Set headers for JSON API
setContentTypeHeaders('application/json', {
  'Accept': 'application/json'
});

// Remove specific headers
removeHeaders(['X-Custom-Header']);
// or remove multiple
removeHeaders(['X-Custom-Header', 'X-Upload-Type']);

File Upload Example

import { setContentTypeHeaders, axiosInstance } from 'swd-axios-query';

function FileUpload() {
  const uploadFile = async (file) => {
    // Set multipart headers for file upload
    setContentTypeHeaders('multipart/form-data');
    
    const formData = new FormData();
    formData.append('file', file);
    
    // Use axiosInstance directly for file upload
    const response = await axiosInstance.post('/upload', formData, {
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    });
    
    return response.data;
  };

  return (
    <input 
      type="file" 
      onChange={(e) => uploadFile(e.target.files[0])} 
    />
  );
}

Direct Axios Instance Usage

Custom API Requests

import { axiosInstance, addHeaders } from 'swd-axios-query';

// For requests outside of React Query hooks
const customApiCall = async () => {
  // Add temporary headers
  addHeaders({ 'X-Request-ID': Date.now().toString() });
  
  try {
    const response = await axiosInstance.get('/custom-endpoint');
    return response.data;
  } catch (error) {
    console.error('Custom API call failed:', error);
    throw error;
  }
};

// Batch requests
const batchRequests = async () => {
  const [users, posts, comments] = await Promise.all([
    axiosInstance.get('/users'),
    axiosInstance.get('/posts'),
    axiosInstance.get('/comments')
  ]);
  
  return {
    users: users.data,
    posts: posts.data,
    comments: comments.data
  };
};

Interceptor Usage

import { 
  addRequestInterceptor, 
  addResponseInterceptor,
  ejectRequestInterceptor,
  ejectResponseInterceptor 
} from 'swd-axios-query';

// Add request interceptor
const requestId = addRequestInterceptor((config) => {
  config.headers['X-Request-ID'] = Date.now().toString();
  return config;
});

// Add response interceptor
const responseId = addResponseInterceptor(
  (response) => {
    console.log('Response received:', response.status);
    return response;
  },
  (error) => {
    console.error('Request failed:', error.message);
    return Promise.reject(error);
  }
);

// Remove interceptors when needed
ejectRequestInterceptor(requestId);
ejectResponseInterceptor(responseId);

Dynamic Header Management

import { addHeaders, getHeaders, removeHeaders } from 'swd-axios-query';

// Check current headers
console.log('Current headers:', getHeaders());

// Add headers conditionally
const addAuthHeader = (token) => {
  if (token) {
    addHeaders({ 'Authorization': `Bearer ${token}` });
  }
};

// Replace all headers (don't merge)
addHeaders({
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}, false); // merge = false

// Remove authentication header
removeHeaders('Authorization');

// Reset to default headers
resetToDefaultHeaders();

Optional & Advanced Features

Axios Request/Response Interceptors

Add or remove Axios interceptors globally for authentication, logging, or error handling.

Add a request interceptor:

import { addRequestInterceptor } from 'swd-axios-query';
const reqId = addRequestInterceptor(config => { /* ... */ return config; });

Add a response interceptor:

import { addResponseInterceptor } from 'swd-axios-query';
const resId = addResponseInterceptor(
  response => response,
  error => Promise.reject(error)
);

Remove an interceptor:

import { ejectRequestInterceptor, ejectResponseInterceptor } from 'swd-axios-query';
ejectRequestInterceptor(reqId);
ejectResponseInterceptor(resId);

Global Loading/Error State Context (Optional)

Track loading and error state for all API requests in your app with a single provider and hook.

Setup:

import { SWDGlobalStatusProvider } from 'swd-axios-query';
<SWDGlobalStatusProvider>
  <App />
</SWDGlobalStatusProvider>

Usage:

import { useGlobalStatus } from 'swd-axios-query';
const { isLoading, error } = useGlobalStatus();
  • This feature is optional. If you don't use the provider, nothing changes in your app.

Contribution & Feedback

We welcome contributions and feedback!

  • Report bugs or request features: Open an issue or pull request.
  • Questions or suggestions: Contact the maintainer or open a discussion.
  • Found a security issue? Please report it privately.

Thank you for using SWD Axios Query!