Skip to main content

Refine provider reference

This page lists what each provider in @taruvi/refine-providers 1.3.7 supports, and the request each Refine call sends. Every provider takes the same @taruvi/sdk Client. For setup, start with Refine integration.

ProviderServes
dataProvider(client)Data table records and edges
storageDataProvider(client)Objects in a storage bucket
appDataProvider(client)App roles, settings, and secrets; function and saved-query runs
userDataProvider(client)Users, their roles, and their apps
authProvider(client)Hosted sign-in, sign-out, the session, and the current user
accessControlProvider(client, options?)useCan, <CanAccess>, and button visibility

functionsDataProvider and analyticsDataProvider are deprecated. Use appDataProvider with useCustom instead.

dataProvider#

The resource name is the table name; set meta.tableName when they differ. Request paths below are relative to /api/apps/APP_SLUG/datatables/TABLE/.

Read records#

GET …/data/
useList<Task>({
resource: 'tasks',
filters: [{field: 'done', operator: 'eq', value: false}],
sorters: [{field: 'title', order: 'asc'}],
pagination: {currentPage: 1, pageSize: 20},
});
  • getList — GET …/data/ with Refine's filters, sorters, and pagination.
  • getOne — GET …/data/ID/.
  • getMany — GET …/data/?id__in=…. Set meta.idColumnName when the primary key isn't id.

Create records#

POST …/data/
const {mutate: create} = useCreate<Task>();
create({resource: 'tasks', values: {title: 'Ship docs', done: false}});
  • create — POST …/data/, or POST …/data/upsert/ with meta.upsert. Returns the created record.
  • createMany — One POST per record. Returns the created records.

Update records#

PATCH …/data/ID/
const {mutate: update} = useUpdate<Task>();
update({resource: 'tasks', id: 'TASK_ID', values: {done: true}});
  • update — PATCH …/data/ID/.
  • updateMany — PATCH …/data/, with each ID merged into the values.

Delete records#

DELETE …/data/ID/
const {mutate: remove} = useDelete<Task>();
remove({resource: 'tasks', id: 'TASK_ID'});
  • deleteOne — DELETE …/data/ID/.
  • deleteMany — DELETE …/data/?ids=, or every record that matches meta.filters with meta.deleteByFilter.
Filtered deletes are permanent

deleteMany with meta.deleteByFilter removes every record that matches meta.filters, not only the IDs you pass. Read with the same filters first.

Custom requests#

custom sends a request to /api/apps/APP_SLUG/datatables/URL, where url is relative to datatables/.

Meta options#

useList({
resource: 'tasks',
meta: {populate: ['assignee'], search: 'launch', allowedActions: ['update', 'delete']},
});
  • tableName — The table to use instead of the resource name. Applies to every method.
  • populate — Relationships to expand, as an array, a comma-separated string, or '*'. For getList, getOne, and getMany.
  • select — The columns to return, for getList.
  • search — Full-text search, for getList.
  • aggregate, groupBy, having — Aggregates such as ['count(*)'], the grouping fields, and a filter on the groups, for getList.
  • allowedActions — ['update', 'delete'], for getList. Each row gains _allowed_actions.
  • idColumnName — The primary key column, for getMany and updateMany. Defaults to id.
  • upsert — Inserts or updates on the primary key, for create.
  • deleteByFilter with filters — Deletes every record that matches meta.filters, for deleteMany.
  • format, include, depth, relationship_type — Graph queries. A graph getList ignores filters, sorters, and pagination. On writes, the operation targets the edge table.

meta.headers is declared on the TaruviMeta type but not applied to requests.

Filter operators#

Refine's operators map to TaruviBase filters:

Refine operatorSent as
eqfield=value
ne, lt, gt, lte, gtefield__ne, field__lt, …
contains, ncontains, startswith, endswith, and their n… formsCase-insensitive matches
containss, startswiths, endswiths, and their n… formsCase-sensitive matches
icontains, istartswith, iendswith, and their n… formsThe same as contains, startswith, and endswith
in, nin, ina, nina, between, nbetweenComma-separated values
null, nnullNull checks
Array and range operators, like, ilike, searchPassed through; wrap the filters in toRefineFilters() to satisfy Refine's types

A filter whose value is undefined, or null with an operator other than null, is skipped. An operator not in this table, such as Refine's eqs, fails the request, at any depth of and/or groups. With meta.deleteByFilter, a filter without a value fails the request instead of being skipped. or and and groups are sent as a filter tree. See Advanced filters.

storageDataProvider#

The resource name is the bucket slug; set meta.bucketName when they differ. Operations that take an id expect the object path: file_path on a listed object, or path on a browsed file. A listed object's own id is a number and doesn't work here. Request paths below are relative to /api/apps/APP_SLUG/storage/buckets/BUCKET/objects/.

List and browse objects#

GET …/objects/browse/?prefix=uploads/
useList({resource: 'documents', meta: {mode: 'browse', prefix: 'uploads/'}});
  • getList — Lists objects with GET …/objects/, filtered and sorted by Refine's filters and sorters. Every condition must match; or groups fail the request.
  • getList with meta: {mode: 'browse', prefix} — Lists the folders and files directly under prefix instead.

getMany isn't supported.

Download a file or read its details#

GET …/objects/PATH/?metadata=true
useOne({resource: 'documents', id: 'reports/q3.pdf', meta: {metadata: true}});

getOne downloads the object as a Blob. With meta.metadata: true, it returns the object's details instead.

Upload files#

POST …/objects/batch-upload/
const {mutate: upload} = useCreate<StorageObject, HttpError, StorageUploadVariables>();
upload({resource: 'documents', values: {files: [file], paths: ['uploads/q3.pdf']}});

create uploads values.files, with optional paths and metadatas matched by index. It returns the first uploaded object.

Update metadata#

update replaces the object's metadata, with PATCH …/objects/PATH/. Visibility follows the bucket and can't be changed per object.

Delete objects#

deleteOne and deleteMany delete objects by path, with POST …/objects/batch-delete/. Objects TaruviBase skips, because they're missing or a policy denies the delete, make the call fail with NotFoundError, ForbiddenError, or TaruviError.

GET …/objects/PATH/edit/
useCustom({
url: 'documents',
method: 'get',
dataProviderName: 'storage',
meta: {kind: 'editAccess', filePath: 'contracts/msa.docx'},
});

custom with meta.kind set to 'viewAccess' or 'editAccess' returns a SharePoint link, {url, mode}, for an Office file. url is the bucket. Other custom calls send a request to …/storage/buckets/URL.

appDataProvider#

Register it as the app provider, and pass dataProviderName: 'app' to its hooks.

Read roles, settings, and secrets#

GET /api/secrets/?keys=app_config,feature_flags
useList({
resource: 'secrets',
dataProviderName: 'app',
meta: {keys: ['app_config', 'feature_flags']},
});
  • useList on roles — The app's roles.
  • useList on secrets — The secrets named in meta.keys. meta.app and meta.includeMetadata are optional.
  • useOne on settings — The app's settings.
  • useOne on secrets — The secret whose key is id. meta.app and meta.tags are optional.

Other operations throw.

Run a function#

useCustom runs its request when the component mounts. To run a function from a button, use useCustomMutation, whose values become the function's params:

src/components/send-report-button.tsx
import {useCustomMutation} from '@refinedev/core';

export function SendReportButton() {
const {mutate, mutation} = useCustomMutation();

return (
<button
type="button"
disabled={mutation.isPending}
onClick={() =>
mutate({
url: 'send-report',
method: 'post',
values: {month: '2026-09'},
dataProviderName: 'app',
meta: {kind: 'function'},
})
}
>
Send report
</button>
);
}

url is the function's slug, and the call returns the function's result. Without meta.async, the function's own mode applies. meta.async: true queues the run and returns the invocation, whose celery_task_id identifies it.

Run a saved query#

POST /api/apps/APP_SLUG/analytics/queries/SLUG/execute/
useCustom({
url: 'revenue-by-month',
method: 'post',
dataProviderName: 'app',
config: {payload: {year: 2026}},
meta: {kind: 'analytics'},
});

url is the saved query's slug, and payload holds its parameters. A run that fails rejects with the SDK's error, with statusCode 400 and code BAD_REQUEST.

userDataProvider#

Register it as the user provider. Any signed-in user can list and read users. Creating, updating, and deleting them needs organization access or a Super Admin app role in one of the site's apps; anyone else's mutation fails with ForbiddenError.

List users#

GET /api/users/
useList({
resource: 'users',
dataProviderName: 'user',
filters: [{field: 'search', operator: 'eq', value: 'ada'}],
pagination: {currentPage: 1, pageSize: 20},
});

Refine filters on search, is_active, is_superuser, is_deleted, and roles apply; other filter fields are ignored. Pagination and the first sorter apply.

Read and manage a user#

  • useOne on users — The user whose username is id. id: 'me' returns the signed-in user.
  • useCreate, useUpdate, useDelete on users — Create, update, or soft-delete a user. id is the username, not the numeric id on list rows.

A user's roles and apps#

useList on roles or apps returns the roles or apps of the user in meta.username.

authProvider#

  • login({callbackUrl?}) — Redirects to hosted sign-in unless a session is stored.
  • register({callbackUrl?}) — Redirects to hosted sign-up.
  • logout({callbackUrl?}) — Clears the stored session, redirects to TaruviBase sign-out, and returns redirectTo: callbackUrl or '/login'. If TaruviBase doesn't accept the return address, the user confirms sign-out on TaruviBase's page.
  • check() — Validates the stored session with TaruviBase. When it isn't valid, returns redirectTo: '/login', which <Authenticated> follows when it has no fallback.
  • onError(error) — On 401, redirects to sign-in. Other errors, including 403, keep the session.
  • getIdentity() — The signed-in user, from GET /api/users/me/.
  • getPermissions() — The signed-in user's roles, permissions, groups, is_staff, and is_superuser.

accessControlProvider#

accessControlProvider(client, {
entityType: (resource) => `datatable:${resource}`,
batchDelayMs: 50,
buttons: {enableAccessControl: true, hideIfUnauthorized: true},
});

Options

  • entityType — Maps a resource name to a policy kind, for checks that don't set one.
  • batchDelayMs — How long to collect useCan checks before sending them as one request. Defaults to 50.
  • buttons.enableAccessControl — Whether Refine's action buttons check access. Defaults to true.
  • buttons.hideIfUnauthorized — Hide, rather than disable, buttons the user can't use. Defaults to true.

Results are cached for 5 minutes. A check without a signed-in user returns can: false.

How a check is sent

  • Kind — params.entityType, then the resource's meta.entityType, then the entityType option, then the resource name. Kinds look like datatable:TABLE or storage:BUCKET.
  • Action — Refine's list and show become read, edit becomes update, and clone becomes create; others are sent unchanged.
  • Record ID — params.id, or * when there is none.
  • Attributes — params, without Refine's resource object and entityType.

See Show only what users may do for the full kind table.

Utilities#

The package also exports the helpers the providers use, for custom providers or useCustom calls: convertRefineFilters, convertRefineSorters, convertRefinePagination, buildRefineQueryParams, convertRefineFiltersToBackendTree, toRefineFilters, and the REFINE_OPERATOR_MAP table above.