Giter Site home page Giter Site logo

Comments (22)

te-online avatar te-online commented on May 4, 2024 6

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.

zachrybaker avatar zachrybaker commented on May 4, 2024 1

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.

sayinmehmet47 avatar sayinmehmet47 commented on May 4, 2024 1

@fzaninotto hiring someone before hired is very reasonable thanks

from react-admin.

fzaninotto avatar fzaninotto commented on May 4, 2024

Hi !

And thanks for your feedback.

  1. 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)
  2. 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.

subcontact avatar subcontact commented on May 4, 2024

Hi, Francois - thanks for the quick response!

  1. Sorry I should have seen the the previous issue!
  2. 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.

fzaninotto avatar fzaninotto commented on May 4, 2024

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.

subcontact avatar subcontact commented on May 4, 2024

Thanks for clarifying. Perhaps it's an item for a feature request

from react-admin.

olegggI avatar olegggI commented on May 4, 2024

@fzaninotto Could you please give more details about how to map our "_id" and "id" in our admin-on-rest?

from react-admin.

fzaninotto avatar fzaninotto commented on May 4, 2024

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.

fzaninotto avatar fzaninotto commented on May 4, 2024

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.

te-online avatar te-online commented on May 4, 2024

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.

zachrybaker avatar zachrybaker commented on May 4, 2024

@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.

zachrybaker avatar zachrybaker commented on May 4, 2024

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.

te-online avatar te-online commented on May 4, 2024

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.

zachrybaker avatar zachrybaker commented on May 4, 2024

@te-online not exactly, no.

from react-admin.

te-online avatar te-online commented on May 4, 2024

@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.

zachrybaker avatar zachrybaker commented on May 4, 2024

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.

djhi avatar djhi commented on May 4, 2024

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.

zachrybaker avatar zachrybaker commented on May 4, 2024

@djhi,

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.

djhi avatar djhi commented on May 4, 2024

I think you can mention it in the miscelanous section of the documentation :)

from react-admin.

sayinmehmet47 avatar sayinmehmet47 commented on May 4, 2024

@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.

fzaninotto avatar fzaninotto commented on May 4, 2024

@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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.