Data Fetching & Data Providers
In a shadcn-admin-kit app, you don’t write API calls using fetch
or axios. Instead, you communicate with your API through an object called the dataProvider
.
This documentation will explain the following concepts:
- What is a Data Provider?
- How to set up a Data Provider
- Supported Data Provider backends
- How to write a Data Provider
- How to query the API using hooks
The dataProvider
Section titled “The dataProvider”Shadcn-admin-kit streamlines data fetching for administrative interfaces through its Data Provider object, which unifies interactions across diverse APIs such as REST and GraphQL. This abstraction allows developers to focus on UI development rather than intricate API calls. It employs specialized hooks, like useGetList
and useGetOne
, and integrates TanStack Query to manage data efficiently, offering features such as caching and optimistic updates.
The framework also simplifies working with relational APIs and incorporates real-time capabilities for collaborative applications. Authentication is handled by an authProvider
, which manages user logins and tokens, subsequently utilized by the dataProvider
for secure API requests.
To learn more about the Data Provider, refer to the Data Fetching documentation.
The first step to using a Data Provider is to pass it to the <Admin>
component via the dataProvider
prop.
For example, let’s use the Simple REST data provider. This provider is suitable for REST APIs using simple GET parameters for filters and sorting.
First, install the ra-data-simple-rest
package:
npm install ra-data-simple-rest
Then, initialize the provider with the REST backend URL, and pass it as the <Admin dataProvider>
:
// in src/App.jsimport { Admin } from "@/components/admin";import { Resource } from 'ra-core';import simpleRestProvider from 'ra-data-simple-rest';
import { PostList } from './posts';
const dataProvider = simpleRestProvider('http://path.to.my.api/');
const App = () => ( <Admin dataProvider={dataProvider}> <Resource name="posts" list={PostList} /> </Admin>);
export default App;
That’s all it takes to make all shadcn-admin-kit components work with your API. They will call the data provider methods, which will in turn call the API. Here’s how the Simple REST data provider maps shadcn-admin-kit calls to API calls:
Method name | API call |
---|---|
getList | GET http://my.api.url/posts?sort=["title","ASC"]&range=[0, 24]&filter={"title":"bar"} |
getOne | GET http://my.api.url/posts/123 |
getMany | GET http://my.api.url/posts?filter={"ids":[123,456,789]} |
getManyReference | GET http://my.api.url/posts?filter={"author_id":345} |
create | POST http://my.api.url/posts |
update | PUT http://my.api.url/posts/123 |
updateMany | Multiple calls to PUT http://my.api.url/posts/123 |
delete | DELETE http://my.api.url/posts/123 |
deleteMany | Multiple calls to DELETE http://my.api.url/posts/123 |
For your own API, look for a compatible data provider in the list of supported API backends or write your own.
For more details about the data provider setup, refer to the Data Provider Setup documentation.
Supported Data Provider Backends
Section titled “Supported Data Provider Backends”Thanks to the Data Provider architecture, shadcn-admin-kit supports a lot of API backends. Check the list below for open-source packages developed and maintained by the core team and developers from the community.
If you can’t find a Data Provider for your backend below, no worries! Writing a Data Provider takes a couple of hours, and won’t prevent you from using shadcn-admin-kit.
Appwrite: marmelab/ra-appwrite
AWS Amplify: MrHertal/react-admin-amplify
Blitz-js: theapexlab/ra-data-blitz
- RConfigurable Identity Property REST Client: zachrybaker/ra-data-rest-client
coreBOS: React-Admin coreBOS Integration
Directus: marmelab/ra-directus
Django Rest Framework: bmihelac/ra-data-django-rest-framework
Eicrud: danyalutsevich/ra-data-eicrud
Eve: smeng9/ra-data-eve
Express & Mongoose: NathanAdhitya/express-mongoose-ra-json-server
Express & Sequelize: express-sequelize-crud
FakeRest: marmelab/ra-data-fakerest
Feathersjs: josx/ra-data-feathers
Firebase Firestore: benwinding/react-admin-firebase.
Firebase Realtime Database: aymendhaya/ra-data-firebase-client.
GeoServer: sergioedo/ra-data-geoserver
Genezio: bogdanripa/react-admin-genezio
Google Sheets: marmelab/ra-data-google-sheets
GraphQL (generic): marmelab/ra-data-graphql (uses Apollo)
GraphQL (simple): marmelab/ra-data-graphql-simple.
- HHAL: b-social/ra-data-hal
Hasura: hasura/ra-data-hasura
Hydra / JSON-LD: api-platform/admin/hydra
IndexedDB (via LocalForage): marmelab/ra-data-local-forage
IndexedDB: tykoth/ra-data-dexie
JSON API: henvo/ra-jsonapi-client
- JJSON HAL: ra-data-json-hal
JSON server: marmelab/ra-data-json-server
LinuxForHealth FHIR: tum-mri-aiim/ra-data-fhir
LocalStorage: marmelab/ra-data-local-storage
LocalStorage (via LocalForage): marmelab/ra-data-local-forage
Loopback3: darthwesker/react-admin-loopback
Loopback4: elmaistrenko/react-admin-lb4
Loopback4 CRUD: loopback4/ra-data-lb4
Mixer: ckoliber/ra-data-mixer
Moleculer Microservices: RancaguaInnova/moleculer-data-provider
NestJS CRUD: rayman1104/ra-data-nestjsx-crud
Nestjs-query (GraphQL): mrnkr/ra-data-nestjs-query
OData: Groopit/ra-data-odata-server
OpenCRUD: weakky/ra-data-opencrud
Parse: almahdi/ra-data-parse
PostGraphile: bowlingx/ra-postgraphile
PostgREST: raphiniert-com/ra-data-postgrest
Prisma v1: weakky/ra-data-prisma
Prisma v2 (GraphQL): panter/ra-data-prisma
Prisma v2 (REST): codeledge/ra-data-simple-prisma
ProcessMaker3: ckoliber/ra-data-processmaker3
REST-HAPI: ra-data-rest-hapi
Sails.js: mpampin/ra-data-json-sails
SQLite: marmelab/ra-sqlite-dataprovider
REST: marmelab/ra-data-simple-rest
Soul/SQLite: DeepBlueCLtd/RA-Soul
Spring Boot: vishpat/ra-data-springboot-rest
Strapi v3/v4: nazirov91/ra-strapi-rest
Strapi v4: garridorafa/ra-strapi-v4-rest
Strapi v5: marmelab/ra-strapi
Supabase: marmelab/ra-supabase
Supabase (GraphQL): @groovestack/ra-data-graphql-supabase
SurrealDB: djedi23/ra-surrealdb
TreeQL / PHP-CRUD-API: nkappler/ra-data-treeql
WooCommerce REST API: zackha/ra-data-woocommerce
That’s a long list!
If you don’t know where to start, use any of the following:
- marmelab/ra-data-fakerest: Simulates an API based on a JSON object. It doesn’t even require a server.
- marmelab/ra-data-json-server: Similar to the previous one, but requires an API powered by JSONServer.
- marmelab/ra-data-simple-rest: A basic REST adapter that reflects the structure of many APIs
- marmelab/ra-data-local-storage: Persists user editions in local storage. This allows local-first apps, and can be useful in tests.
- marmelab/ra-data-local-forage: Uses a local, offline database based on IndexedDB. Falls back to WebSQL or localStorage.
Tip: Since dataProviders all present the same interface, you can use one dataProvider during early prototyping / development phases, then switch to the dataProvider that fits your production infrastructure.
If you’ve written a Data Provider for another backend, and open-sourced it, please help complete this list with your package.
Writing a Data Provider
Section titled “Writing a Data Provider”APIs are so diverse that quite often, none of the available Data Providers suit you API. In such cases, you’ll have to write your own Data Provider. Don’t worry, it usually takes only a couple of hours.
A data provider must implement the following methods:
const dataProvider = { // get a list of records based on sort, filter, and pagination getList: (resource, params) => Promise, // get a single record by id getOne: (resource, params) => Promise, // get a list of records based on an array of ids getMany: (resource, params) => Promise, // get the records referenced to another record, e.g. comments for a post getManyReference: (resource, params) => Promise, // create a record create: (resource, params) => Promise, // update a record based on a patch update: (resource, params) => Promise, // update a list of records based on an array of ids and a common patch updateMany: (resource, params) => Promise, // delete a record by id delete: (resource, params) => Promise, // delete a list of records based on an array of ids deleteMany: (resource, params) => Promise,}
To call the data provider, shadcn-admin-kit combines a method (e.g. getOne
), a resource (e.g. ‘posts’) and a set of parameters.
Tip: In comparison, HTTP requests require a verb (e.g. ‘GET’), an url (e.g. ‘http://myapi.com/posts’), a list of headers (like Content-Type) and a body.
To learn more about writing a Data Provider, refer to the Data Provider Writing documentation.
Querying The API
Section titled “Querying The API”Shadcn-admin-kit provides special hooks to emit read and write queries to the dataProvider
, which in turn sends requests to your API. Under the hood, it uses React Query to call the dataProvider
and cache the results.
Shadcn-admin-kit provides one query hook for each of the Data Provider read methods. They are useful shortcuts that make your code more readable and more robust. The query hooks execute on mount. They return an object with the following properties: { data, isPending, error }. Query hooks are:
useGetList
callsdataProvider.getList()
useGetOne
callsdataProvider.getOne()
useGetMany
callsdataProvider.getMany()
useGetManyReference
callsdataProvider.getManyReference()
Their input signature is the same as the related dataProvider method, i.e. they expect the resource name and the query parameters:
const { isPending, error, data } = useGetOne(resource, { id });// calls dataProvider.getOne(resource, { id })
For instance, here is how to fetch one User record on mount using the useGetOne hook:
import { useGetOne } from 'ra-core';import { Loading, Error } from './MyComponents';
const UserProfile = ({ userId }) => { const { isPending, error, data: user } = useGetOne('users', { id: userId });
if (isPending) return <Loading />; if (error) return <Error />; if (!user) return null;
return ( <ul> <li>Name: {user.name}</li> <li>Email: {user.email}</li> </ul> )};
Shadcn-admin-kit also provides one mutation hook for each of the Data Provider write methods. These hooks execute the query when you call a callback. They return an array with the following items: [mutate, { data, isPending, error }]
. mutate
is a callback that you can call to execute the mutation.
Mutation hooks are:
useCreate
callsdataProvider.create()
useUpdate
callsdataProvider.update()
useUpdateMany
callsdataProvider.updateMany()
useDelete
callsdataProvider.delete()
useDeleteMany
callsdataProvider.deleteMany()
Their input signature is the same as the related dataProvider method, e.g.:
const [update, { isPending, error, data }] = useUpdate(resource, { id, data, previousData });// calls dataProvider.update(resource, { id, data, previousData })
For instance, here is a button that updates a comment record when clicked, using the useUpdate hook:
import { useUpdate, useRecordContext } from 'ra-core';
const ApproveButton = () => { const record = useRecordContext(); const [approve, { isPending }] = useUpdate('comments', { id: record.id, data: { isApproved: true }, previousData: record }); return <button onClick={() => approve()} disabled={isPending}>Approve</button>;};
For more information and examples, refer to the Data Fetching documentation.