К основному содержанию
правило

axios — правило для Cursor: HTTP-клиент без хаоса

Задаёт ИИ-агенту в Cursor единый стиль работы с axios: общий инстанс, модули API, перехватчики и отмена запросов. Пригодится, когда компоненты уже пестрят разными вызовами.

Установить в Cursor · Вручную: положить файлы Все способы и платформы ↓
.cursor/rules/axios.mdc
Открыть на GitHub

Что делает axios

Правило подключается файлом .cursor/rules/axios.mdc и действует на файлы **/*.{js,jsx}. Внутри — четыре раздела практики: один инстанс apiClient с baseURL, таймаутом и заголовками по умолчанию; вынос эндпоинтов в модули вроде src/api/users.js; перехватчики для токена и общей обработки ошибок; отмена запросов через AbortController в useEffect.

Каждый пункт идёт парой примеров: как не надо и как надо. Агент видит разницу на конкретном коде, поэтому подсказки в духе «вынеси запрос из компонента» он будет давать сразу в нужной форме. Заодно правило фиксирует, что CancelToken устарел: если попросите отмену, получите AbortController.

Глобсы ограничены .js и .jsx, так что на .ts/.tsx правило не сработает, хотя примеры из него переносятся на TypeScript почти без правок. Импорт axios прямо в компоненте и захардкоженный адрес в примерах помечены как ошибка, поэтому код на fetch рядом с apiClient агент тоже начнёт переписывать — это стоит держать в голове, если клиент используется только частично.

Какие задачи решает

  • свести все запросы к одному настроенному инстансу axios
  • вынести вызовы API из React-компонентов в отдельные модули
  • подставлять токен авторизации автоматически через перехватчик
  • отменять запрос при размонтировании компонента без утечек
  • заменить устаревший CancelToken на AbortController

Примеры запросов агенту

  • Создай инстанс axios для проекта по правилам из .cursor/rules/axios.mdc
  • Отрефактори UserList.jsx: вынеси запросы в src/api/users.js и обработай ошибки
  • Добавь отмену запроса через AbortController в DataFetcher.jsx

Как установить axios

Вручную: положить файлы

.cursor/rules/axios.mdc

Во frontmatter: description, globs, alwaysApply

По шагам, с командами для каждой платформы: Cursor rules: файлы .mdc, четыре режима и замена .cursorrules

Вопросы о axios

Как установить правило axios в Cursor?

Поместите файл .cursor/rules/axios.mdc в каталог .cursor/rules/ в корне проекта. Cursor подхватит его автоматически для файлов, попадающих под маску **/*.{js,jsx}.

Что делает правило axios в Cursor?

Оно описывает агенту, как писать HTTP-клиент на axios: единый apiClient, модули на каждый эндпоинт, перехватчики для авторизации и ошибок, отмена через AbortController. Каждый совет подкреплён примерами плохого и хорошего кода.

Почему в правиле AbortController, а не CancelToken?

CancelToken в axios объявлен устаревшим, поэтому правило требует отменять запросы через AbortController. В примере это сделано в очистке useEffect.

Исходный текст

axios.mdc · CC0-1.0
---
description: Definitive guidelines for using axios to build robust, maintainable, and performant HTTP clients in JavaScript/React applications.
globs: **/*.{js,jsx}
---
# axios Best Practices

`axios` is the go-to HTTP client for modern JavaScript applications due to its robust features and promise-based API. These guidelines ensure your team leverages `axios` effectively, promoting clean code, centralized logic, and predictable error handling.

## 1. Centralize Your `axios` Instance

Always create a single, pre-configured `axios` instance for your application. This centralizes `baseURL`, `timeout`, and default headers, adhering to the DRY principle and simplifying configuration changes.

❌ BAD: Scattered `axios` calls
```javascript
// In component A
axios.get('https://api.example.com/users', { timeout: 5000 });

// In component B
axios.post('https://api.example.com/products', data, { headers: { 'Content-Type': 'application/json' } });
```

✅ GOOD: Dedicated `apiClient` instance
```javascript
// src/api/apiClient.js
import axios from 'axios';

const apiClient = axios.create({
  baseURL: process.env.REACT_APP_API_BASE_URL || 'https://api.example.com',
  timeout: 10000, // 10 seconds
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
  },
});

export default apiClient;
```

## 2. Abstract API Endpoints into Modules

Encapsulate each API endpoint or resource into its own module. This promotes the single-responsibility principle, making your API calls testable, reusable, and easy to understand.

❌ BAD: API logic directly in components
```javascript
// src/components/UserList.jsx
import React, { useEffect, useState } from 'react';
import axios from 'axios'; // Direct axios import

function UserList() {
  const [users, setUsers] = useState([]);
  useEffect(() => {
    axios.get('https://api.example.com/users') // Hardcoded URL
      .then(response => setUsers(response.data))
      .catch(error => console.error(error));
  }, []);
  // ...
}
```

✅ GOOD: Dedicated API service modules
```javascript
// src/api/users.js
import apiClient from './apiClient'; // Use the centralized instance

export const getUsers = async () => {
  const response = await apiClient.get('/users');
  return response.data;
};

export const createUser = async (userData) => {
  const response = await apiClient.post('/users', userData);
  return response.data;
};

// src/components/UserList.jsx
import React, { useEffect, useState } from 'react';
import { getUsers } from '../api/users'; // Import specific API functions

function UserList() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchUsers = async () => {
      try {
        const data = await getUsers();
        setUsers(data);
      } catch (err) {
        setError('Failed to fetch users.'); // User-friendly error
        console.error(err); // Log original error for debugging
      } finally {
        setLoading(false);
      }
    };
    fetchUsers();
  }, []);

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

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}
```

## 3. Leverage Interceptors for Global Logic

Use `axios` interceptors for cross-cutting concerns like authentication, global error handling, logging, or request/response transformations. This keeps your API functions clean and focused on data fetching.

### Request Interceptors (e.g., Auth Tokens)

Inject authentication tokens automatically into every request.

```javascript
// src/api/apiClient.js (continued)
apiClient.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('authToken'); // Or from a state management solution
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);
```

### Response Interceptors (e.g., Global Error Handling)

Handle common error statuses (e.g., 401 Unauthorized, 500 Server Error) globally. Map raw errors to user-friendly messages.

```javascript
// src/api/apiClient.js (continued)
apiClient.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;

    // Handle 401 Unauthorized globally
    if (error.response?.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      // Example: Redirect to login page or attempt token refresh
      console.warn('Unauthorized request, redirecting to login...');
      // window.location.href = '/login'; // Or dispatch a global event
      return Promise.reject(new Error('Session expired. Please log in again.')); // Return a user-friendly error
    }

    // Map other HTTP errors to user-friendly messages
    let errorMessage = 'An unexpected error occurred.';
    if (axios.isAxiosError(error)) {
      if (error.response) {
        // Server responded with a status other than 2xx
        errorMessage = error.response.data?.message || `Server Error: ${error.response.status}`;
      } else if (error.request) {
        // Request was made but no response received
        errorMessage = 'No response from server. Please check your internet connection.';
      } else {
        // Something else happened while setting up the request
        errorMessage = error.message;
      }
    } else {
      errorMessage = error.message || 'An unknown error occurred.';
    }

    console.error('API Error:', error); // Log full error for debugging
    return Promise.reject(new Error(errorMessage)); // Propagate user-friendly error
  }
);
```

## 4. Implement Request Cancellation with `AbortController`

Prevent memory leaks and unnecessary network activity, especially in React components that might unmount before a request completes. Always use `AbortController` for cancellation; `CancelToken` is deprecated.

❌ BAD: Ignoring cancellation or using deprecated `CancelToken`
```javascript
// In a React component
useEffect(() => {
  axios.get('/long-running-data').then(...); // Request might complete after component unmounts
}, []);

// Using deprecated CancelToken
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/data', { cancelToken: source.token });
source.cancel('Operation cancelled.');
```

✅ GOOD: Using `AbortController` in `useEffect` cleanup
```javascript
// src/components/DataFetcher.jsx
import React, { useEffect, useState } from 'react';
import apiClient from '../api/apiClient';
import axios from 'axios'; // Import axios to use axios.isCancel

function DataFetcher() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const controller = new AbortController(); // Create AbortController
    const signal = controller.signal;

    const fetchData = async () => {
      try {
        setLoading(true);
        setError(null);
        const response = await apiClient.get('/some-data', { signal }); // Pass signal to axios
        setData(response.data);
      } catch (err) {
        if (axios.isCancel(err)) {
          console.log('Request cancelled:', err.message);
        } else {
          setError(err.message); // Use the user-friendly message from interceptor
          console.error('Fetch error:', err);
        }
      } finally {
        setLoading(false);
      }
    };

    fetchData();

    return () => {
      controller.abort('Component unmounted'); // Abort request on cleanup
    };
  }, []);

  if (loading) return <div>Loading data...</div>;
  if (error) return <div>Error: {error}</div>;
  return <div>{JSON.stringify(data)}</div>;
}
```

## 5. Validate Payloads Before Sending

Always validate request payloads on the client-side before sending them to the server. This reduces unnecessary network requests and provides immediate feedback to the user.

❌ BAD: Sending potentially invalid data
```javascript
const handleSubmit = async (formData) => {
  // No client-side validation
  await createUser(formData);
};
```

✅ GOOD: Client-side validation
```javascript
import { createUser } from '../api/users';

const handleSubmit = async (formData) => {
  if (!formData.name || formData.name.length < 3) {
    alert('Name must be at least 3 characters.');
    return;
  }
  if (!formData.email || !/^\S+@\S+\.\S+$/.test(formData.email)) {
    alert('Please enter a valid email address.');
    return;
  }

  try {
    await createUser(formData);
    alert('User created successfully!');
  } catch (error) {
    alert(`Failed to create user: ${error.message}`); // Display user-friendly error
  }
};
```

## 6. Use TypeScript for API Contracts

Define explicit TypeScript interfaces for your request payloads and response data. This improves maintainability, provides compile-time safety, and enhances developer experience with autocompletion.

```typescript
// src/types/api.ts
export interface User {
  id: number;
  name: string;
  email: string;
}

export interface CreateUserPayload {
  name: string;
  email: string;
  password?: string;
}

// src/api/users.ts (example with TypeScript)
import apiClient from './apiClient';
import { User, CreateUserPayload } from '../types/api';

export const getUsers = async (): Promise<User[]> => {
  const response = await apiClient.get<User[]>('/users');
  return response.data;
};

export const createUser = async (userData: CreateUserPayload): Promise<User> => {
  const response = await apiClient.post<User>('/users', userData);
  return response.data;
};
```

## 7. Test API Interactions with Mocking

For unit and integration tests, mock `axios` requests to avoid making actual network calls. This makes tests faster, more reliable, and independent of external API availability. `axios-mock-adapter` is a common choice.

```javascript
// src/api/users.test.js
import MockAdapter from 'axios-mock-adapter';
import apiClient from './apiClient';
import { getUsers, createUser } from './users';

const mock = new MockAdapter(apiClient);

describe('users API', () => {
  afterEach(() => {
    mock.reset(); // Reset mocks after each test
  });

  it('should fetch users successfully', async () => {
    const mockUsers = [{ id: 1, name: 'Alice', email: '[email protected]' }];
    mock.onGet('/users').reply(200, mockUsers);

    const users = await getUsers();
    expect(users).toEqual(mockUsers);
  });

  it('should create a user successfully', async () => {
    const newUserPayload = { name: 'Bob', email: '[email protected]' };
    const createdUser = { id: 2, ...newUserPayload };
    mock.onPost('/users').reply(201, createdUser);

    const user = await createUser(newUserPayload);
    expect(user).toEqual(createdUser);
  });

  it('should handle API errors gracefully', async () => {
    mock.onGet('/users').reply(500, { message: 'Internal Server Error' });

    await expect(getUsers()).rejects.toThrow('Server Error: 500'); // Based on interceptor error message
  });
});
```

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Похожие правила IDE

Все правила IDE по теме «Фронтенд и UI» →
Senior Frontend Developer ozcanzaferayan Промпт, который заставляет ChatGPT писать фронтенд-код одним файлом на заданном стеке. Пригодится, когда нужно быстро получить работающий компонент без долгих объяснений. GP ChatGPT ★ 174 831звёзд репо typescript-write metabase Скилл для написания и редактирования TypeScript и JavaScript кода с соблюдением стандартов Metabase. Требует строгую типизацию без any и проверку типов перед завершением. CX Codex +1 2 100установок dynamic-import patterns.dev Обучает агента разделять бандл через dynamic import(). Скилл помогает отложить загрузку тяжёлых библиотек и диалогов до действий пользователя. CX Codex +1 1 500установок virtual-lists patterns.dev Обучает агента технике виртуализации списков и таблиц в веб-приложениях. Помогает убрать задержки при скролле и ускорить начальную отрисовку страниц. CX Codex +1 1 500установок react18-lifecycle-patterns официальный github Переводит устаревшие методы жизненного цикла классовых компонентов на стандарт React 18.3.1. Пригодится при подготовке легаси-кода к React 19. 743установок api-design margelo Скилл помогает проектировать и проверять публичные API библиотек на TypeScript, JavaScript, React и React Native. CX Codex +1 609установок

Из того же набора240

Весь набор →
beautifulsoup4 Задаёт стандарты парсинга HTML на Python: выбор lxml, работа с CSS-селекторами и валидация структур через Pydantic. ★ 3 580звёзд репо bash Правило задаёт стиль для Bash-скриптов: обработка ошибок, кавычки, переменные и структура кода. Подходит для проектов, где скрипты проходят через Cursor. ★ 3 580звёзд репо azure Правило для Cursor с набором требований к коду и инфраструктуре в Azure: IaC, безопасность, экономия ресурсов. Пригодится, если проект живёт в Azure. ★ 3 580звёзд репо azure-pipelines Задаёт правила написания YAML-пайплайнов для Azure DevOps: многостадийные сборки, шаблоны, кеширование и безопасность секретов. ★ 3 580звёзд репо aws Задаёт агенту стандарты разработки на AWS: только CDK v2, переиспользование окружения Lambda, идемпотентность и минимальные права IAM. ★ 3 580звёзд репо aws-rds Набор инструкций для Cursor по безопасной работе с AWS RDS. Помогает писать чистый SQL, изолировать сетевой доступ и защищать учётные данные. ★ 3 580звёзд репо aws-lambda Правило помогает проектировать Lambda-функции с учётом структуры кода, безопасности, производительности и тестирования. Полезно при разработке или проверке бессерверного приложения на AWS. ★ 3 580звёзд репо aws-ecs Правило для Cursor с набором требований к контейнерам на AWS ECS: неизменяемые образы, секреты из Secrets Manager, логи в stdout. Пригодится, когда агент пишет Dockerfile и task definition. ★ 3 580звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой