Helper library for Strapi plugins development providing React components, hooks, utilities, and TypeScript types for building plugin interfaces
—
The @strapi/helper-plugin package provides 18+ utility functions for common operations including HTTP client creation, error handling, data transformation, authentication, file operations, and internationalization. These utilities ensure consistent functionality across Strapi plugins.
Functions for creating HTTP clients, making requests, and handling network operations.
// Create configured HTTP client
interface FetchClient {
get: <TData = any, R = AxiosResponse<TData>, TSend = any>(
url: string,
config?: AxiosRequestConfig<TSend>
) => Promise<R>;
put: <TData = any, R = AxiosResponse<TData>, TSend = any>(
url: string,
data?: TSend,
config?: AxiosRequestConfig<TSend>
) => Promise<R>;
post: <TData = any, R = AxiosResponse<TData>, TSend = any>(
url: string,
data?: TSend,
config?: AxiosRequestConfig<TSend>
) => Promise<R>;
del: <TData = any, R = AxiosResponse<TData>, TSend = any>(
url: string,
config?: AxiosRequestConfig<TSend>
) => Promise<R>;
}
function getFetchClient(defaultOptions?: AxiosRequestConfig): FetchClient;
// Legacy request function (deprecated)
interface RequestOptions extends RequestInit {
params?: Record<string, string>;
}
function request<ResponseType = unknown>(
url: string,
options?: RequestOptions,
shouldWatchServerRestart?: boolean,
stringify?: boolean,
config?: { noAuth?: boolean }
): Promise<ResponseType>;
// Wrap axios instance with custom functionality
function wrapAxiosInstance(
instance: AxiosInstance,
options?: AxiosRequestConfig
): AxiosInstance;
// Promise error handling utility
function awaitToJs<T, U = Error>(
promise: Promise<T>,
errorExt?: object
): Promise<[U, undefined] | [null, T]>;Usage Examples:
// Create HTTP client
const client = getFetchClient({
timeout: 5000,
headers: { 'X-Custom': 'value' }
});
// Make requests
const articles = await client.get<Article[]>('/api/articles');
const created = await client.post<Article>('/api/articles', articleData);
// Error handling with awaitToJs
const [error, result] = await awaitToJs(
client.get('/api/articles')
);
if (error) {
console.error('Request failed:', error);
} else {
console.log('Articles:', result);
}Functions for processing, normalizing, and extracting error information from API responses.
// Extract inner errors from API responses
interface GetAPIInnerErrorsOptions {
getTrad: (id: string) => string;
}
function getAPIInnerErrors(
error: AxiosError<{ error: ApiError }>,
options: GetAPIInnerErrorsOptions
): Record<string, MessageDescriptor> | string | undefined;
// Normalize API error responses
interface NormalizeErrorOptions {
name?: string;
intlMessagePrefixCallback?: (id: string) => string;
}
interface NormalizeErrorReturn {
id: string;
defaultMessage: string;
name?: string;
values: Record<'path', string> | Record<string, never>;
}
function normalizeAPIError(
apiError: AxiosError<{ error: ApiError }>,
intlMessagePrefixCallback?: (id: string) => string
): NormalizeErrorReturn | {
name: string;
message: string | null;
errors: NormalizeErrorReturn[]
} | null;
// Extract Yup validation errors
function getYupInnerErrors(yupError: any): Record<string, any>;
// Translated error constants
const translatedErrors: {
readonly email: 'components.Input.error.validation.email';
readonly json: 'components.Input.error.validation.json';
readonly lowercase: 'components.Input.error.validation.lowercase';
readonly max: 'components.Input.error.validation.max';
readonly maxLength: 'components.Input.error.validation.maxLength';
readonly min: 'components.Input.error.validation.min';
readonly minLength: 'components.Input.error.validation.minLength';
readonly regex: 'components.Input.error.validation.regex';
readonly required: 'components.Input.error.validation.required';
readonly unique: 'components.Input.error.validation.unique';
readonly integer: 'component.Input.error.validation.integer';
};Usage Examples:
// Handle API errors
const handleError = (error: AxiosError) => {
const normalized = normalizeAPIError(error, (id) => `errors.${id}`);
if (normalized && 'errors' in normalized) {
// Handle validation errors
normalized.errors.forEach(err => {
console.error(`Field ${err.values.path}: ${err.defaultMessage}`);
});
} else if (normalized) {
// Handle single error
console.error(normalized.defaultMessage);
}
};
// Use translated errors
const errorMessage = translatedErrors.required; // 'components.Input.error.validation.required'Functions for managing authentication tokens and browser storage.
// User information interface
interface UserInfo {
email: string;
firstname?: string;
lastname?: string;
username?: string;
preferedLanguage?: string;
id: number;
isActive?: boolean;
blocked: boolean;
createdAt: string;
updatedAt: string;
}
// Storage items interface
interface StorageItems {
userInfo: UserInfo;
jwtToken: string;
STRAPI_THEME: 'light' | 'dark';
GUIDED_TOUR_CURRENT_STEP: string | null;
GUIDED_TOUR_COMPLETED_STEPS: string[] | null;
GUIDED_TOUR_SKIPPED: boolean | null;
STRAPI_UPDATE_NOTIF: boolean | null;
STRAPI_UPLOAD_MODAL_VIEW: 0 | 1 | null;
STRAPI_UPLOAD_LIBRARY_VIEW: 0 | 1 | null;
videos: unknown;
onboarding: unknown;
}
// Auth utility object (deprecated)
const auth: {
clear: <T extends keyof StorageItems>(key: T) => void;
clearAppStorage: () => void;
get: <T extends keyof StorageItems>(key: T) => StorageItems[T] | null;
set: (value: any, key: keyof StorageItems, isLocalStorage: boolean) => void;
// Deprecated methods
getToken: (tokenKey?: 'jwtToken') => string | null;
setToken: (value?: any, isLocalStorage?: boolean, tokenKey?: 'jwtToken') => void;
clearToken: (tokenKey?: 'jwtToken') => void;
getUserInfo: (userInfoKey?: 'userInfo') => UserInfo | null;
setUserInfo: (value: any, isLocalStorage?: boolean, userInfo?: 'userInfo') => void;
clearUserInfo: (userInfoKey?: 'userInfo') => void;
updateToken: (value?: any) => void;
};Usage Examples:
// Manage authentication tokens
const token = auth.get('jwtToken');
if (token) {
// User is authenticated
}
// Store user preferences
auth.set('light', 'STRAPI_THEME', true);
// Clear authentication data
auth.clearAppStorage(); // Clears all auth-related storage while preserving preferencesFunctions for checking and validating user permissions.
// Permission type definitions
interface Permission {
id?: Entity.ID;
action: string;
actionParameters?: object;
subject?: string | null;
properties?: {
fields?: string[];
locales?: string[];
[key: string]: any;
};
conditions?: string[];
}
type PermissionToCheckAgainst = Pick<Permission, 'action' | 'subject'> &
Partial<Pick<Permission, 'actionParameters' | 'conditions' | 'properties'>>;
// Permission checking functions
function hasPermissions(
userPermissions: Permission[],
permissions: PermissionToCheckAgainst[],
signal?: GenericAbortSignal
): Promise<boolean>;
function findMatchingPermissions(
userPermissions: Permission[],
permissions: PermissionToCheckAgainst[]
): Permission[];
function formatPermissionsForRequest(permissions: Permission[]): Partial<Permission>[];
function shouldCheckPermissions(permissions: Permission[]): boolean;Usage Examples:
// Check if user has permissions
const canCreateArticles = await hasPermissions(
userPermissions,
[{ action: 'create', subject: 'api::article.article' }]
);
if (canCreateArticles) {
// Show create button
}
// Find matching permissions for multiple actions
const matchingPermissions = findMatchingPermissions(
userPermissions,
[
{ action: 'read', subject: 'api::article.article' },
{ action: 'update', subject: 'api::article.article' }
]
);Functions for data processing, formatting, and manipulation.
// Calculate difference between objects/arrays
function difference<T>(original: T, comparison: T): Partial<T>;
// Content type data formatting
function formatContentTypeData<
TSchema extends Schema.ContentType,
TData extends { [K in keyof TSchema['attributes']]: Attribute.GetValue<TSchema['attributes'][K]> }
>(
data: TData,
contentTypeSchema: TSchema,
componentSchema: Record<string, Schema.Component>
): TData;
// Remove fields from content data
function contentManagementUtilRemoveFieldsFromData<
TSchema extends Schema.ContentType,
TData extends { [K in keyof TSchema['attributes']]: Attribute.GetValue<TSchema['attributes'][K]> }
>(
data: TData,
contentTypeSchema: TSchema,
componentSchema: Record<string, Schema.Component>,
fields?: string[]
): TData;Usage Examples:
// Calculate object differences
const changes = difference(originalData, modifiedData);
console.log('Changed fields:', changes);
// Format data for editing
const editableData = formatContentTypeData(
rawData,
contentTypeSchema,
componentSchemas
);
// Clean data before submission
const cleanData = contentManagementUtilRemoveFieldsFromData(
formData,
contentTypeSchema,
componentSchemas,
['createdAt', 'updatedAt'] // Additional fields to remove
);Functions for handling file operations and URL manipulation.
// Extract file extension from filename
function getFileExtension(filename: string): string;
// Prefix file URLs with backend URL
function prefixFileUrlWithBackendUrl(fileURL: string): string;
// Prefix plugin translation keys
function prefixPluginTranslations(
translations: Record<string, string>,
pluginId: string
): Record<string, string>;Usage Examples:
// Get file extension
const extension = getFileExtension('document.pdf'); // Returns: 'pdf'
// Build complete file URL
const fullUrl = prefixFileUrlWithBackendUrl('/uploads/image.jpg');
// Returns: 'http://localhost:1337/uploads/image.jpg'
// Prefix translation keys
const prefixedTranslations = prefixPluginTranslations(
{
'button.save': 'Save',
'button.cancel': 'Cancel'
},
'my-plugin'
);
// Returns: { 'my-plugin.button.save': 'Save', 'my-plugin.button.cancel': 'Cancel' }Functions for styling, layout, and user interface operations.
// Convert pixels to rem units
function pxToRem(px: number): string;
// Set opacity on hex color values
function setHexOpacity(hex: string, opacity: number): string;
// Stop event propagation
function stopPropagation(event: Event): void;Usage Examples:
// Convert pixels to rem
const remValue = pxToRem(16); // Returns: '1rem'
const spacing = pxToRem(24); // Returns: '1.5rem'
// Adjust color opacity
const semiTransparentBlue = setHexOpacity('#0066cc', 0.5); // Returns: '#0066cc80'
// Stop event propagation
const handleClick = (event: React.MouseEvent) => {
stopPropagation(event);
// Handle click without bubbling
};Specialized utilities for content management operations (also documented in Content Manager section).
// Get schema attribute type information
function getType(schema: Schema.Schema, attrName: string): string;
// Get nested attribute information
function getOtherInfos(schema: Schema.Schema, path: string[]): any;Usage Examples:
// Get field type from schema
const fieldType = getType(contentTypeSchema, 'title'); // Returns: 'string'
// Get component information
const componentUid = getOtherInfos(schema, ['myComponent', 'component']);
const isRepeatable = getOtherInfos(schema, ['myComponent', 'repeatable']);// Create comprehensive error handler
const createErrorHandler = () => {
return async (operation: () => Promise<any>) => {
const [error, result] = await awaitToJs(operation());
if (error) {
const normalized = normalizeAPIError(error);
if (normalized) {
// Handle normalized error
console.error(normalized.defaultMessage);
}
throw error;
}
return result;
};
};
// Usage
const safeApiCall = createErrorHandler();
const articles = await safeApiCall(() => client.get('/api/articles'));// Create content processing utility
const processContentData = (
data: any,
schema: Schema.ContentType,
components: Record<string, Schema.Component>
) => {
// Format for editing
const formatted = formatContentTypeData(data, schema, components);
// Calculate differences
const changes = difference(data, formatted);
// Clean for submission
const cleaned = contentManagementUtilRemoveFieldsFromData(
formatted,
schema,
components
);
return { formatted, changes, cleaned };
};// Create plugin utility bundle
const createPluginUtils = (pluginId: string) => {
const client = getFetchClient();
const prefixTranslations = (translations: Record<string, string>) =>
prefixPluginTranslations(translations, pluginId);
const handleError = (error: AxiosError) => {
const normalized = normalizeAPIError(error);
// Handle error appropriately
};
return {
client,
prefixTranslations,
handleError,
pxToRem,
setHexOpacity,
getFileExtension
};
};getFetchClient should be called once per component/modulehasPermissions with abort signals for cancellable requestsrequest function is deprecated; use useFetchClient hook insteadauth utility methods are deprecated; use direct storage accessInstall with Tessl CLI
npx tessl i tessl/npm-strapi--helper-plugin