I am trying to Use Cockpit CMS as a Rest Backend, however i fail to understand the Logic of the Rest Provider and the Resource. Apparently we call GET_LIST first - which works fine, resource params etc is set. but it also calls GET_MANY with an emtpy Resource. As you can see i replaced
url = `${apiUrl}/${resource}?${stringify(query)}`;
with
url = `${apiUrl}/collections/get/testing?token=SOMETOKEN&filter[_id]=5e2037a536383609f00001cc`;
which produces no error, but i fail to understand why resource is emtpy/undefined at the get_many call.
App.js:
import React from 'react';
import authProvider from './cockpitAuthProvider';
import { Admin, Resource, ListGuesser } from 'react-admin';
import simpleRestProvider from './simpleRestProviderlistCollections';
const App = () => (
<Admin authProvider={authProvider} dataProvider={simpleRestProvider('http://someurl/cockpit-0.9.3/api')}>
<Resource name="testing" list={ListGuesser} />
</Admin>
);
export default App;
simpleRestProviderlistCollections.js:
import { stringify } from 'query-string';
import {
fetchUtils,
GET_LIST,
GET_ONE,
GET_MANY,
GET_MANY_REFERENCE,
CREATE,
UPDATE,
UPDATE_MANY,
DELETE,
DELETE_MANY,
} from 'react-admin';
**
* Maps react-admin queries to a simple REST API
*
* The REST dialect is similar to the one of FakeRest
* @see https://github.com/marmelab/FakeRest
* @example
* GET_LIST => GET http://my.api.url/posts?sort=['title','ASC']&range=[0, 24]
* GET_ONE => GET http://my.api.url/posts/123
* GET_MANY => GET http://my.api.url/posts?filter={ids:[123,456,789]}
* UPDATE => PUT http://my.api.url/posts/123
* CREATE => POST http://my.api.url/posts
* DELETE => DELETE http://my.api.url/posts/123
*/
export default (apiUrl, httpClient = fetchUtils.fetchJson) => {
/**
* @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
* @param {String} resource Name of the resource to fetch, e.g. 'posts'
* @param {Object} params The data request params, depending on the type
* @returns {Object} { url, options } The HTTP request parameters
*/
const convertDataRequestToHTTP = (type, resource, params) => {
let url = '';
console.log(`convertDataRequestToHTTP ${resource}`);
const options = {};
switch (type) {
case GET_LIST: {
console.log(`convertDataRequestToHTTP GET_LIST ${resource}`);
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
sort: JSON.stringify([field, order]),
range: JSON.stringify([
(page - 1) * perPage,
page * perPage - 1,
]),
filter: JSON.stringify(params.filter),
};
//added a / before ?
//url = `${apiUrl}/${resource}/get/?${stringify(query)}`;
url = `${apiUrl}/collections/get/${resource}?token=SOMETOKEN`;
break;
}
case GET_ONE:
url = `${apiUrl}/${resource}/${params.id}`;
break;
case GET_MANY: {
console.log(`convertDataRequestToHTTP GET_MANY ${resource}`);
const query = {
filter: JSON.stringify({ id: params.ids }),
};
//url = `${apiUrl}/${resource}?${stringify(query)}`;
url = `${apiUrl}/collections/get/testing?token=SOMETOKEN&filter[_id]=5e2037a536383609f00001cc`;
break;
}
case GET_MANY_REFERENCE: {
console.log("convertDataRequestToHTTP GET_MANY_REFERENCE");
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
sort: JSON.stringify([field, order]),
range: JSON.stringify([
(page - 1) * perPage,
page * perPage - 1,
]),
filter: JSON.stringify({
...params.filter,
[params.target]: params.id,
}),
};
url = `${apiUrl}/${resource}?${stringify(query)}`;
break;
}
case UPDATE:
url = `${apiUrl}/${resource}/${params.id}`;
options.method = 'PUT';
options.body = JSON.stringify(params.data);
break;
case CREATE:
url = `${apiUrl}/${resource}`;
options.method = 'POST';
options.body = JSON.stringify(params.data);
break;
case DELETE:
url = `${apiUrl}/${resource}/${params.id}`;
options.method = 'DELETE';
break;
default:
throw new Error(`Unsupported fetch action type ${type}`);
}
return { url, options };
};
/**
* @param {Object} response HTTP response from fetch()
* @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
* @param {String} resource Name of the resource to fetch, e.g. 'posts'
* @param {Object} params The data request params, depending on the type
* @returns {Object} Data response
*/
const convertHTTPResponse = (response, type, resource, params) => {
const { headers, json } = response;
switch (type) {
case GET_LIST:
var jnew = json.entries
return {
data: jnew.map(resource => ({ ...resource, id: resource._id }) ),
total: 1,
};
case GET_MANY_REFERENCE:
var jnew = json.entries
console.log(json)
return {
data: jnew.map(resource => ({ ...resource, id: resource._id }) ),
total: 1,
};
case CREATE:
return { data: { ...params.data, id: json._id } };
default:
return { data: json };
}
};
/**
* @param {string} type Request type, e.g GET_LIST
* @param {string} resource Resource name, e.g. "posts"
* @param {Object} payload Request parameters. Depends on the request type
* @returns {Promise} the Promise for a data response
*/
return (type, resource, params) => {
// simple-rest doesn't handle filters on UPDATE route, so we fallback to calling UPDATE n times instead
if (type === UPDATE_MANY) {
return Promise.all(
params.ids.map(id =>
httpClient(`${apiUrl}/${resource}/${id}`, {
method: 'PUT',
body: JSON.stringify(params.data),
})
)
).then(responses => ({
data: responses.map(response => response.json),
}));
}
// simple-rest doesn't handle filters on DELETE route, so we fallback to calling DELETE n times instead
if (type === DELETE_MANY) {
return Promise.all(
params.ids.map(id =>
httpClient(`${apiUrl}/${resource}/${id}`, {
method: 'DELETE',
})
)
).then(responses => ({
data: responses.map(response => response.json),
}));
}
const { url, options } = convertDataRequestToHTTP(
type,
resource,
params
);
console.log(resource)
console.log(options)
console.log(url)
return httpClient(url, options).then(response =>
convertHTTPResponse(response, type, resource, params)
);
};
};
this also seems to be the problem at the question/solution of: How is the correct way to have multiple dataProviders in react-admin?
Because if i do it the way of the solution i also get the error:
TypeError: dataProviderMapping.dataProvider is not a function
due to the emtpy resource.
i also tried this: https://github.com/marmelab/react-admin/blob/master/packages/ra-data-json-server/src/index.ts implementation which should work like this:
getList GET http://my.api.url/posts?_sort=title&_order=ASC&_start=0&_end=24&title=bar
getMany GET http://my.api.url/posts/123, GET http://my.api.url/posts/456, GET http://my.api.url/posts/789
however, in my case it produces http://my.api.url/s/123 (s because resource is empty)
Api Returns: http://192.168.0.163/cockpit-0.9.3/api/collections/get/testing?token=TOKEN
{"fields":{"bla":{"name":"bla","type":"text","localize":false,"options":[]},"blup":{"name":"blup","type":"text","localize":false,"options":[]}},"entries":[{"bla":"dgfhs","blup":"sdgfh","_mby":"5ddc222d36383611fa00025a","_by":"5ddc222d36383611fa00025a","_modified":1579169696,"_created":1579169696,"_id":"5e2037a036383609f0000270"},{"bla":"sgdf","blup":"sdfg","_mby":"5ddc222d36383611fa00025a","_by":"5ddc222d36383611fa00025a","_modified":1579169701,"_created":1579169701,"_id":"5e2037a536383609f00001cc"}],"total":2}
{
"fields": {
"bla": {
"name": "bla",
"type": "text",
"localize": false,
"options": []
},
"blup": {
"name": "blup",
"type": "text",
"localize": false,
"options": []
}
},
"entries": [
{
"bla": "sgdf",
"blup": "sdfg",
"_mby": "5ddc222d36383611fa00025a",
"_by": "5ddc222d36383611fa00025a",
"_modified": 1579169701,
"_created": 1579169701,
"_id": "5e2037a536383609f00001cc"
}
],
"total": 1
}