0
# Utilities
1
2
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.
3
4
## HTTP & Network Utilities
5
6
Functions for creating HTTP clients, making requests, and handling network operations.
7
8
```typescript { .api }
9
// Create configured HTTP client
10
interface FetchClient {
11
get: <TData = any, R = AxiosResponse<TData>, TSend = any>(
12
url: string,
13
config?: AxiosRequestConfig<TSend>
14
) => Promise<R>;
15
put: <TData = any, R = AxiosResponse<TData>, TSend = any>(
16
url: string,
17
data?: TSend,
18
config?: AxiosRequestConfig<TSend>
19
) => Promise<R>;
20
post: <TData = any, R = AxiosResponse<TData>, TSend = any>(
21
url: string,
22
data?: TSend,
23
config?: AxiosRequestConfig<TSend>
24
) => Promise<R>;
25
del: <TData = any, R = AxiosResponse<TData>, TSend = any>(
26
url: string,
27
config?: AxiosRequestConfig<TSend>
28
) => Promise<R>;
29
}
30
31
function getFetchClient(defaultOptions?: AxiosRequestConfig): FetchClient;
32
33
// Legacy request function (deprecated)
34
interface RequestOptions extends RequestInit {
35
params?: Record<string, string>;
36
}
37
38
function request<ResponseType = unknown>(
39
url: string,
40
options?: RequestOptions,
41
shouldWatchServerRestart?: boolean,
42
stringify?: boolean,
43
config?: { noAuth?: boolean }
44
): Promise<ResponseType>;
45
46
// Wrap axios instance with custom functionality
47
function wrapAxiosInstance(
48
instance: AxiosInstance,
49
options?: AxiosRequestConfig
50
): AxiosInstance;
51
52
// Promise error handling utility
53
function awaitToJs<T, U = Error>(
54
promise: Promise<T>,
55
errorExt?: object
56
): Promise<[U, undefined] | [null, T]>;
57
```
58
59
**Usage Examples:**
60
61
```typescript
62
// Create HTTP client
63
const client = getFetchClient({
64
timeout: 5000,
65
headers: { 'X-Custom': 'value' }
66
});
67
68
// Make requests
69
const articles = await client.get<Article[]>('/api/articles');
70
const created = await client.post<Article>('/api/articles', articleData);
71
72
// Error handling with awaitToJs
73
const [error, result] = await awaitToJs(
74
client.get('/api/articles')
75
);
76
77
if (error) {
78
console.error('Request failed:', error);
79
} else {
80
console.log('Articles:', result);
81
}
82
```
83
84
## Error Handling Utilities
85
86
Functions for processing, normalizing, and extracting error information from API responses.
87
88
```typescript { .api }
89
// Extract inner errors from API responses
90
interface GetAPIInnerErrorsOptions {
91
getTrad: (id: string) => string;
92
}
93
94
function getAPIInnerErrors(
95
error: AxiosError<{ error: ApiError }>,
96
options: GetAPIInnerErrorsOptions
97
): Record<string, MessageDescriptor> | string | undefined;
98
99
// Normalize API error responses
100
interface NormalizeErrorOptions {
101
name?: string;
102
intlMessagePrefixCallback?: (id: string) => string;
103
}
104
105
interface NormalizeErrorReturn {
106
id: string;
107
defaultMessage: string;
108
name?: string;
109
values: Record<'path', string> | Record<string, never>;
110
}
111
112
function normalizeAPIError(
113
apiError: AxiosError<{ error: ApiError }>,
114
intlMessagePrefixCallback?: (id: string) => string
115
): NormalizeErrorReturn | {
116
name: string;
117
message: string | null;
118
errors: NormalizeErrorReturn[]
119
} | null;
120
121
// Extract Yup validation errors
122
function getYupInnerErrors(yupError: any): Record<string, any>;
123
124
// Translated error constants
125
const translatedErrors: {
126
readonly email: 'components.Input.error.validation.email';
127
readonly json: 'components.Input.error.validation.json';
128
readonly lowercase: 'components.Input.error.validation.lowercase';
129
readonly max: 'components.Input.error.validation.max';
130
readonly maxLength: 'components.Input.error.validation.maxLength';
131
readonly min: 'components.Input.error.validation.min';
132
readonly minLength: 'components.Input.error.validation.minLength';
133
readonly regex: 'components.Input.error.validation.regex';
134
readonly required: 'components.Input.error.validation.required';
135
readonly unique: 'components.Input.error.validation.unique';
136
readonly integer: 'component.Input.error.validation.integer';
137
};
138
```
139
140
**Usage Examples:**
141
142
```typescript
143
// Handle API errors
144
const handleError = (error: AxiosError) => {
145
const normalized = normalizeAPIError(error, (id) => `errors.${id}`);
146
147
if (normalized && 'errors' in normalized) {
148
// Handle validation errors
149
normalized.errors.forEach(err => {
150
console.error(`Field ${err.values.path}: ${err.defaultMessage}`);
151
});
152
} else if (normalized) {
153
// Handle single error
154
console.error(normalized.defaultMessage);
155
}
156
};
157
158
// Use translated errors
159
const errorMessage = translatedErrors.required; // 'components.Input.error.validation.required'
160
```
161
162
## Authentication & Storage Utilities
163
164
Functions for managing authentication tokens and browser storage.
165
166
```typescript { .api }
167
// User information interface
168
interface UserInfo {
169
email: string;
170
firstname?: string;
171
lastname?: string;
172
username?: string;
173
preferedLanguage?: string;
174
id: number;
175
isActive?: boolean;
176
blocked: boolean;
177
createdAt: string;
178
updatedAt: string;
179
}
180
181
// Storage items interface
182
interface StorageItems {
183
userInfo: UserInfo;
184
jwtToken: string;
185
STRAPI_THEME: 'light' | 'dark';
186
GUIDED_TOUR_CURRENT_STEP: string | null;
187
GUIDED_TOUR_COMPLETED_STEPS: string[] | null;
188
GUIDED_TOUR_SKIPPED: boolean | null;
189
STRAPI_UPDATE_NOTIF: boolean | null;
190
STRAPI_UPLOAD_MODAL_VIEW: 0 | 1 | null;
191
STRAPI_UPLOAD_LIBRARY_VIEW: 0 | 1 | null;
192
videos: unknown;
193
onboarding: unknown;
194
}
195
196
// Auth utility object (deprecated)
197
const auth: {
198
clear: <T extends keyof StorageItems>(key: T) => void;
199
clearAppStorage: () => void;
200
get: <T extends keyof StorageItems>(key: T) => StorageItems[T] | null;
201
set: (value: any, key: keyof StorageItems, isLocalStorage: boolean) => void;
202
203
// Deprecated methods
204
getToken: (tokenKey?: 'jwtToken') => string | null;
205
setToken: (value?: any, isLocalStorage?: boolean, tokenKey?: 'jwtToken') => void;
206
clearToken: (tokenKey?: 'jwtToken') => void;
207
getUserInfo: (userInfoKey?: 'userInfo') => UserInfo | null;
208
setUserInfo: (value: any, isLocalStorage?: boolean, userInfo?: 'userInfo') => void;
209
clearUserInfo: (userInfoKey?: 'userInfo') => void;
210
updateToken: (value?: any) => void;
211
};
212
```
213
214
**Usage Examples:**
215
216
```typescript
217
// Manage authentication tokens
218
const token = auth.get('jwtToken');
219
if (token) {
220
// User is authenticated
221
}
222
223
// Store user preferences
224
auth.set('light', 'STRAPI_THEME', true);
225
226
// Clear authentication data
227
auth.clearAppStorage(); // Clears all auth-related storage while preserving preferences
228
```
229
230
## Permission Utilities
231
232
Functions for checking and validating user permissions.
233
234
```typescript { .api }
235
// Permission type definitions
236
interface Permission {
237
id?: Entity.ID;
238
action: string;
239
actionParameters?: object;
240
subject?: string | null;
241
properties?: {
242
fields?: string[];
243
locales?: string[];
244
[key: string]: any;
245
};
246
conditions?: string[];
247
}
248
249
type PermissionToCheckAgainst = Pick<Permission, 'action' | 'subject'> &
250
Partial<Pick<Permission, 'actionParameters' | 'conditions' | 'properties'>>;
251
252
// Permission checking functions
253
function hasPermissions(
254
userPermissions: Permission[],
255
permissions: PermissionToCheckAgainst[],
256
signal?: GenericAbortSignal
257
): Promise<boolean>;
258
259
function findMatchingPermissions(
260
userPermissions: Permission[],
261
permissions: PermissionToCheckAgainst[]
262
): Permission[];
263
264
function formatPermissionsForRequest(permissions: Permission[]): Partial<Permission>[];
265
266
function shouldCheckPermissions(permissions: Permission[]): boolean;
267
```
268
269
**Usage Examples:**
270
271
```typescript
272
// Check if user has permissions
273
const canCreateArticles = await hasPermissions(
274
userPermissions,
275
[{ action: 'create', subject: 'api::article.article' }]
276
);
277
278
if (canCreateArticles) {
279
// Show create button
280
}
281
282
// Find matching permissions for multiple actions
283
const matchingPermissions = findMatchingPermissions(
284
userPermissions,
285
[
286
{ action: 'read', subject: 'api::article.article' },
287
{ action: 'update', subject: 'api::article.article' }
288
]
289
);
290
```
291
292
## Data Transformation Utilities
293
294
Functions for data processing, formatting, and manipulation.
295
296
```typescript { .api }
297
// Calculate difference between objects/arrays
298
function difference<T>(original: T, comparison: T): Partial<T>;
299
300
// Content type data formatting
301
function formatContentTypeData<
302
TSchema extends Schema.ContentType,
303
TData extends { [K in keyof TSchema['attributes']]: Attribute.GetValue<TSchema['attributes'][K]> }
304
>(
305
data: TData,
306
contentTypeSchema: TSchema,
307
componentSchema: Record<string, Schema.Component>
308
): TData;
309
310
// Remove fields from content data
311
function contentManagementUtilRemoveFieldsFromData<
312
TSchema extends Schema.ContentType,
313
TData extends { [K in keyof TSchema['attributes']]: Attribute.GetValue<TSchema['attributes'][K]> }
314
>(
315
data: TData,
316
contentTypeSchema: TSchema,
317
componentSchema: Record<string, Schema.Component>,
318
fields?: string[]
319
): TData;
320
```
321
322
**Usage Examples:**
323
324
```typescript
325
// Calculate object differences
326
const changes = difference(originalData, modifiedData);
327
console.log('Changed fields:', changes);
328
329
// Format data for editing
330
const editableData = formatContentTypeData(
331
rawData,
332
contentTypeSchema,
333
componentSchemas
334
);
335
336
// Clean data before submission
337
const cleanData = contentManagementUtilRemoveFieldsFromData(
338
formData,
339
contentTypeSchema,
340
componentSchemas,
341
['createdAt', 'updatedAt'] // Additional fields to remove
342
);
343
```
344
345
## File & URL Utilities
346
347
Functions for handling file operations and URL manipulation.
348
349
```typescript { .api }
350
// Extract file extension from filename
351
function getFileExtension(filename: string): string;
352
353
// Prefix file URLs with backend URL
354
function prefixFileUrlWithBackendUrl(fileURL: string): string;
355
356
// Prefix plugin translation keys
357
function prefixPluginTranslations(
358
translations: Record<string, string>,
359
pluginId: string
360
): Record<string, string>;
361
```
362
363
**Usage Examples:**
364
365
```typescript
366
// Get file extension
367
const extension = getFileExtension('document.pdf'); // Returns: 'pdf'
368
369
// Build complete file URL
370
const fullUrl = prefixFileUrlWithBackendUrl('/uploads/image.jpg');
371
// Returns: 'http://localhost:1337/uploads/image.jpg'
372
373
// Prefix translation keys
374
const prefixedTranslations = prefixPluginTranslations(
375
{
376
'button.save': 'Save',
377
'button.cancel': 'Cancel'
378
},
379
'my-plugin'
380
);
381
// Returns: { 'my-plugin.button.save': 'Save', 'my-plugin.button.cancel': 'Cancel' }
382
```
383
384
## UI Utilities
385
386
Functions for styling, layout, and user interface operations.
387
388
```typescript { .api }
389
// Convert pixels to rem units
390
function pxToRem(px: number): string;
391
392
// Set opacity on hex color values
393
function setHexOpacity(hex: string, opacity: number): string;
394
395
// Stop event propagation
396
function stopPropagation(event: Event): void;
397
```
398
399
**Usage Examples:**
400
401
```typescript
402
// Convert pixels to rem
403
const remValue = pxToRem(16); // Returns: '1rem'
404
const spacing = pxToRem(24); // Returns: '1.5rem'
405
406
// Adjust color opacity
407
const semiTransparentBlue = setHexOpacity('#0066cc', 0.5); // Returns: '#0066cc80'
408
409
// Stop event propagation
410
const handleClick = (event: React.MouseEvent) => {
411
stopPropagation(event);
412
// Handle click without bubbling
413
};
414
```
415
416
## Content Manager Utilities
417
418
Specialized utilities for content management operations (also documented in Content Manager section).
419
420
```typescript { .api }
421
// Get schema attribute type information
422
function getType(schema: Schema.Schema, attrName: string): string;
423
424
// Get nested attribute information
425
function getOtherInfos(schema: Schema.Schema, path: string[]): any;
426
```
427
428
**Usage Examples:**
429
430
```typescript
431
// Get field type from schema
432
const fieldType = getType(contentTypeSchema, 'title'); // Returns: 'string'
433
434
// Get component information
435
const componentUid = getOtherInfos(schema, ['myComponent', 'component']);
436
const isRepeatable = getOtherInfos(schema, ['myComponent', 'repeatable']);
437
```
438
439
## Utility Integration Patterns
440
441
### Error Handling Pipeline
442
443
```typescript
444
// Create comprehensive error handler
445
const createErrorHandler = () => {
446
return async (operation: () => Promise<any>) => {
447
const [error, result] = await awaitToJs(operation());
448
449
if (error) {
450
const normalized = normalizeAPIError(error);
451
452
if (normalized) {
453
// Handle normalized error
454
console.error(normalized.defaultMessage);
455
}
456
457
throw error;
458
}
459
460
return result;
461
};
462
};
463
464
// Usage
465
const safeApiCall = createErrorHandler();
466
const articles = await safeApiCall(() => client.get('/api/articles'));
467
```
468
469
### Content Processing Pipeline
470
471
```typescript
472
// Create content processing utility
473
const processContentData = (
474
data: any,
475
schema: Schema.ContentType,
476
components: Record<string, Schema.Component>
477
) => {
478
// Format for editing
479
const formatted = formatContentTypeData(data, schema, components);
480
481
// Calculate differences
482
const changes = difference(data, formatted);
483
484
// Clean for submission
485
const cleaned = contentManagementUtilRemoveFieldsFromData(
486
formatted,
487
schema,
488
components
489
);
490
491
return { formatted, changes, cleaned };
492
};
493
```
494
495
### Plugin Utilities Bundle
496
497
```typescript
498
// Create plugin utility bundle
499
const createPluginUtils = (pluginId: string) => {
500
const client = getFetchClient();
501
502
const prefixTranslations = (translations: Record<string, string>) =>
503
prefixPluginTranslations(translations, pluginId);
504
505
const handleError = (error: AxiosError) => {
506
const normalized = normalizeAPIError(error);
507
// Handle error appropriately
508
};
509
510
return {
511
client,
512
prefixTranslations,
513
handleError,
514
pxToRem,
515
setHexOpacity,
516
getFileExtension
517
};
518
};
519
```
520
521
## Performance Considerations
522
523
- **HTTP Client Caching**: `getFetchClient` should be called once per component/module
524
- **Error Processing**: Normalize errors early to avoid repeated processing
525
- **Data Transformation**: Cache processed data when possible
526
- **Permission Checks**: Use `hasPermissions` with abort signals for cancellable requests
527
- **Storage Operations**: Batch storage operations when updating multiple items
528
529
## Migration Notes
530
531
- `request` function is deprecated; use `useFetchClient` hook instead
532
- `auth` utility methods are deprecated; use direct storage access
533
- Many utilities include deprecation warnings for smooth migration to newer APIs