Comments (22)
Coming back to my question, I'd like to answer it myself, for people coming from search-engines 🤓
Rest clients are now called dataProvider
https://marmelab.com/react-admin/DataProviders.html.
The documentation gives examples on what a dataProvider script/function should include.
Basically, what the exported function in the dataProvider
is supposed to do is map react-admin's
internal requests for specific resources to a URL at your REST service and then map the response of the service to a format the internal store understands.
To create a dataProvider, start by creating a dataProvider.js
and reference it in your App.js
like so:
import jsonServerProvider from './dataProvider';
const dataProvider = jsonServerProvider('https://example.org/rest-api');
const App = () => (
<Admin dataProvider={dataProvider}>
...
</Admin>
};
from react-admin.
My Typescript and ECMAScript is a little rusty, but I think I managed to figure out how to roll and npm publish my own data provider, based on ra-data-simple-rest, since that seems to be what is needed to support my existing real-world data.
It allows you to specify via a single simple json hash, say in your app.js, the resources that don't actually use 'id' for their identifier. React-admin will operate fine b/c on its side they use 'id', but the data provider translates to the real identifier property name on your behalf.
It can be found in my github at zachrybaker/ra-data-rest-client and in npm.
// app.js
import customKeysDataProvider from 'ra-data-rest-client';
const customKeysHash = {
'testKVP': 'key'
};
const dataProvider = customKeysDataProvider('https://localhost:44377/api', customKeysHash);
const App = () => (
<Admin dashboard={Dashboard} dataProvider={dataProvider}>
<Resource name="testKVP" list={TestKVPList} edit={TestKVPEdit} create={TestKVPCreate} icon={ViewListIcon} />
</Admin>
);
Hopefully this will help others get up and running with a large pre-existing web service that can't be modified to play by react-admin's terms.
@fzaninotto I saw in documentation an appeal to let your team know of data providers. Hopefully this is helpful!
#5290
from react-admin.
@fzaninotto hiring someone before hired is very reasonable thanks
from react-admin.
Hi !
And thanks for your feedback.
- you'll have to map your id name with
id
in the REST client. The name is compulsory. As for ythe type, it shouldn't be integer-only. the fact that it currently is is a bug (cf #7) - The REST client does whatever you want in to do ; it's pure JS. if you need to aggregate multiple API endpoints before giving back the control to admin-on-rest, feel free to do it.
2.1 Embedded documents are not yet supported, but they should be fairly easy to deal with. You'll need to write your own Field
and Input
components though.
from react-admin.
Hi, Francois - thanks for the quick response!
- Sorry I should have seen the the previous issue!
- Is there an existing object reference or method/class I can call to re-use the data that's already present? EG a reference from the last REST call. That way I'm dealing with an API rather than making separate AJAX calls to the same services and it ensures the data is in sync with the UI, and re-use caching or anything that may be implemented in the future.
EG (using posts and comments as the example - embedding comments with posts)
if (resource === "posts")
comments = commentsList.getById(resourceId)
from react-admin.
No, if you need some form of intermediate persistence / caching, you'll have to implement it yourself in the REST client. Alternatively, you could put some of this logic in a custom saga.
from react-admin.
Thanks for clarifying. Perhaps it's an item for a feature request
from react-admin.
@fzaninotto Could you please give more details about how to map our "_id" and "id" in our admin-on-rest?
from react-admin.
How about something like that:
const convertHTTPResponseToREST = (response, type, resource, params) => {
const { headers, json } = response;
switch (type) {
case GET_LIST:
case GET_MANY_REFERENCE:
if (!headers.has('content-range')) {
throw new Error('The Content-Range header is missing in the HTTP Response. The simple REST client expects responses for lists of resources to contain this header with the total number of results to build the pagination. If you are using CORS, did you declare Content-Range in the Access-Control-Expose-Headers header?');
}
return {
data: json.map(record => ({ id: record._id, ...record })),
total: parseInt(headers.get('content-range').split('/').pop(), 10),
};
case CREATE:
return { data: { id: json._id, ...params.data } };
default:
return { data: { id: json._id, ...json } };
}
};
from react-admin.
Added to the FAQ: https://marmelab.com/admin-on-rest/FAQ.html#can-i-have-custom-identifiers-primary-keys-for-my-resources
from react-admin.
Excuse my maybe dumb question, but how do I actually get to a custom rest client? I mean everything is in place, I don't want to reinvent the wheel, just map the primary key. My main question being: Where should I put the code displayed here: https://marmelab.com/admin-on-rest/FAQ.html#can-i-have-custom-identifiers-primary-keys-for-my-resources?
from react-admin.
@te-online thanks for that heads up on the documentation.
I actually got pretty far into building a demo app that worked with a real server to CRUD objects against SQL via an auto-generated data access layer, when I found the subtle requirement that your key has to be "id" to use the ra-data-simple-rest data provider.
I guess in their latest parlance I need to write some sort of data adapter that changes "payload" for the query for those types to use the key name I need?
It seems like it would be much LESS of a headache and less work to supply the data provider some sort of key-value JSON blob that defines the key map overrides by their type, in a simple init method option.
That's literally all I need, as it wasn't too much work to create the server-side API that conforms to the client's needs otherwise.
Without this, it seems I either have to go touch a lot of files (4 per data type on the server side) to fudge an id alias property, or I have to go extend the data provider to add a lot of wrapping calls just to get it to use a different key name for queries. Too bad, this tool otherwise really lowers the bar for adding a CRUD interface for an existing system. I have 250+ types of objects I have to touch...That's a lot of work.
Someone please tell me I'm missing something?
from react-admin.
So I started into what I was proposing above, adding another argument to the constructor to ra-data-simple-rest import call to specify a blob of key names by resource.
What I quickly found is that unfortunately the ra-core itself builds the payloads and has a pretty tight dependency on key names being "id." It seems baked in the module at multiple levels, unfortunately.
In other words, there is a tight/hard API dependency between ra-core and anything that would work with it, not just at the data provider, that it plays by ra-core's rules - which is that 'id' is your id parameter.
from react-admin.
I'm not sure if I understand your problem. But I've used react-admin
with REST APIs that use uuid
instead of id
.
// dataProvider.js
// ... imports
export default (apiUrls, httpClient = fetchUtils.fetchJson) => {
// ...
const convertHTTPResponse = (response, type, resource, params) => {
const { headers, json } = response;
switch (type) {
case GET_LIST:
case GET_MANY_REFERENCE:
// Apply transformations
if (json.data) {
json.data = json.data.map((document) => {
return applyDocumentFilters(document);
});
}
if (!headers.has('x-total-count')) {
throw new Error(
'The X-Total-Count header is missing in the HTTP Response. The jsonServer Data Provider expects responses for lists of resources to contain this header with the total number of results to build the pagination. If you are using CORS, did you declare X-Total-Count in the Access-Control-Expose-Headers header?'
);
}
return {
data: json.data,
total: parseInt(headers.get('x-total-count').split('/').pop(), 10)
};
case CREATE:
return { data: { ...params.data, id: json.data.uuid } };
default:
if (json.data && json.data.length > 0) {
// Apply transformations
json.data = json.data.map((document) => {
return applyDocumentFilters(document);
});
return { data: json.data };
} else if (json.data && json.data.constructor.name.toLowerCase() === 'object') {
json.data = applyDocumentFilters(json.data);
return { data: json.data, id: json.data.uuid };
}
return { data: [] };
}
};
// ...
const applyDocumentFilters = (document) => {
// Apply id from uuid parameter if necessary.
document.id = document.id || document.uuid;
// ...
return document;
};
return (type, resource, params) => {
const apiUrl = getAPIUrl(resource);
// ...
const { url, options } = convertDataRequestToHTTP(type, resource, params);
return httpClient(url, options).then((response) => convertHTTPResponse(response, type, resource, params));
};
};
from react-admin.
@te-online not exactly, no.
from react-admin.
@zachrybaker Okay, cool that you solved it :-) Just to be clear, you don't have to publish an npm package for your custom data provider. You can create a JavaScript file in your project and then import your data provider from that file.
This page didn't help you in terms of documentation? https://marmelab.com/react-admin/DataProviders.html
What do you think needs to be improved? :-)
from react-admin.
The package is for reuse and for others, as packages go. There's a PR out there #5290 to bring that into the provider list, as this is undoubtedly generic enough yet helpful for others.
Honestly I'm pretty fresh on react and react-admin, so I may not be the best person to ask, b/c I'm still learning to think more react-y, but IMO that page would do well to re-emphasize the hard requirement on 'id' being your identifier property name, at a minimum.
For me there was a lot to understand even after reading that page before I knew what I needed to do conceptually, and then as is sometimes typical, actually implementing an alternate data provider really brought it all together for me, mentally-speaking.
from react-admin.
IMO that page would do well to re-emphasize the hard requirement on 'id' being your identifier property name, at a minimum.
See https://marmelab.com/react-admin/DataProviders.html#response-format
A {Record} is an object literal with at least an id property, e.g. { id: 123, title: "hello, world" }.
I think it does already. Anyway, your dataProvider is indeed a good idea. Good job 👍
from react-admin.
Quick documentation question.
I've published a .NetCore REST server zachrybaker/React-Admin-RestServer that speaks the react-admin dialect you guys chose and works nicely with #5290 or the default provider.
It basically bootstraps the process of getting your resources exposed by [re]generating your data access layer from examining a database for you, and you just have to pick what you actually expose from that.
Do you guys document any server API projects or know any existing place to mention this that others might find it?
Thanks in advance.
from react-admin.
I think you can mention it in the miscelanous section of the documentation :)
from react-admin.
@fzaninotto can you create an example in sandbox or repo for that. I am trying to find solution for that. I couldn't understand the document to change my primary key to _id. I take my data from MongoDB and my objects id are start with _id. So please make example...
from react-admin.
@sayinmehmet47 Sorry, we can't provide a CodeSandbox running against MongoDB as MongoDB doesn't come with a native HTTP API.
Also, we've documented how to map _id to id in https://marmelab.com/admin-on-rest/FAQ.html#can-i-have-custom-identifiers-primary-keys-for-my-resources. If that's not enough for you, then I suggest you hire a React / React-admin expert to guide you through the dataProvider logic.
from react-admin.
Related Issues (20)
- `TextInput` component not handling events during the initial life cycles HOT 4
- combineDataProviders does not support more than 2 parameters in custom dataProvider methods HOT 1
- `CoreAdminUI` wraps everything in a `<div>` HOT 2
- useWatch on fields with required in edit is not working HOT 1
- The 'QueryClient' type does not have queryCache, mutationCache, defaultOptions, queryDefaults and four other properties of the 'QueryClient' type. HOT 3
- CheckboxGroupInput : disabling some of the checkboxes Feature HOT 3
- Bug / Breaking change without major for useTheme behaviour HOT 5
- Multiple expandable datagrids: expanding a row triggers all datagrids to expand HOT 2
- AutocompleteInput in ReferenceArrayInput with dynamic choices shows empty field on selection HOT 5
- Property "resource" in SortButtonProps not involved HOT 2
- Change title property type in core display components <Edit>, <Show>, <View> HOT 1
- Standalone version of the Store for a dual-store strategy HOT 3
- Unable to clear default value in DateTimeInput component HOT 2
- Documented theme level defaultProps overrides do not work for react admin components HOT 4
- Reference Array selected item from a filter query vanishes immediately after selection. HOT 2
- Infinite re-rendering using disabled AutocompleteArrayInput in a ReferenceArrayInput HOT 6
- AutocompleteInput don't keep focus with mouse HOT 5
- Documentation update in sample. HOT 3
- NumberInput's `onBlur` prop does not provide an event object HOT 2
- Add ability to customize query string format for lists HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from react-admin.