从Admin-On-REST 教程开始后,我尝试使用自定义REST-Client 实现将应用程序绑定到我现有的 ArangoDB 后端。后端公开了一个简单的自动生成的“默认”FOXX HTTP API。
这基本上与simple client
. 为了更好地集成,我的目标是使用基于json client
. 因此我将文件复制admin-on-rest/src/rest/jsonServer.js
到我的项目中。我将其修改为该文件内容:
import { stringify } from 'query-string';
import { fetchJson, flattenObject } from 'admin-on-rest';
import {
GET_LIST,
GET_ONE,
GET_MANY,
GET_MANY_REFERENCE,
CREATE,
UPDATE,
DELETE,
} from 'admin-on-rest';
/**
* Maps admin-on-rest queries to a json-server powered REST API
*
* @see https://github.com/typicode/json-server
* @example
* GET_LIST => GET http://my.api.url/posts?_sort=title&_order=ASC&_start=0&_end=24
* GET_ONE => GET http://my.api.url/posts/123
* GET_MANY => GET http://my.api.url/posts/123, GET http://my.api.url/posts/456, GET http://my.api.url/posts/789
* UPDATE => PUT http://my.api.url/posts/123
* CREATE => POST http://my.api.url/posts/123
* DELETE => DELETE http://my.api.url/posts/123
*/
export default (apiUrl, httpClient = 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 REST request params, depending on the type
* @returns {Object} { url, options } The HTTP request parameters
*/
const convertRESTRequestToHTTP = (type, resource, params) => {
let url = '';
const options = {};
switch (type) {
case GET_LIST: {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
...flattenObject(params.filter),
_sort: field,
_order: order,
_start: (page - 1) * perPage,
_end: page * perPage,
};
url = `${apiUrl}/${resource}?${stringify(query)}`;
break;
}
case GET_ONE:
url = `${apiUrl}/${resource}/${params.id}`;
break;
case GET_MANY_REFERENCE: {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
...flattenObject(params.filter),
[params.target]: params.id,
_sort: field,
_order: order,
_start: (page - 1) * perPage,
_end: page * perPage,
};
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 REST request params, depending on the type
* @returns {Object} REST response
*/
const convertHTTPResponseToREST = (response, type, resource, params) => {
const { headers, json } = response;
switch (type) {
case GET_LIST:
return {
data: json.map((obj) => {
obj.id = obj._key;
delete obj['_key'];
return obj;
}),
total: headers.get('X-Total-Count')
};
case GET_MANY_REFERENCE:
if (!headers.has('x-total-count')) {
throw new Error(
'The X-Total-Count header is missing in the HTTP Response. The jsonServer 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 X-Total-Count in the Access-Control-Expose-Headers header?'
);
}
return {
data: json,
total: parseInt(
headers
.get('x-total-count')
.split('/')
.pop(),
10
),
};
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 REST response
*/
return (type, resource, params) => {
// json-server doesn't handle WHERE IN requests, so we fallback to calling GET_ONE n times instead
if (type === GET_MANY) {
return Promise.all(
params.ids.map(id => httpClient(`${apiUrl}/${resource}/${id}`))
).then(responses => ({
data: responses.map(response => response.json),
}));
}
const { url, options } = convertRESTRequestToHTTP(
type,
resource,
params
);
return httpClient(url, options).then(response =>
convertHTTPResponseToREST(response, type, resource, params)
);
};
};
它很像原版 - 我只编辑过:
import
顶部的部分- 该部分的
convertHTTPResponseToREST
方法GET_LIST
。
最后,我通过文件将其导入应用程序App.js
,使其看起来像:
import CustomRestClientJson from './CustomRestClientJson'
const App = () => (
<Admin restClient={CustomRestClientJson('http://localhost:8529/_db/orgraph/admin')}>
<Resource name="assets" list={AssetList} />
</Admin>
);
问题是:
a.)尝试加载数据时,应用程序在浏览器中失败并出现错误(由客户端方法Object(...) is not a function
中的调用引发)。...flattenObject(params.filter)
convertRESTRequestToHTTP
b.) 或者yarn
当我将客户端的导入语句从以下位置更改时构建/编译失败:
import { stringify } from 'query-string';
import { fetchJson, flattenObject } from 'admin-on-rest';
import {
GET_LIST,
GET_ONE,
GET_MANY,
GET_MANY_REFERENCE,
CREATE,
UPDATE,
DELETE,
} from 'admin-on-rest';
至:
import { stringify } from 'query-string';
import { fetchJson, flattenObject } from 'admin-on-rest/src/util/fetch';
import {
GET_LIST,
GET_ONE,
GET_MANY,
GET_MANY_REFERENCE,
CREATE,
UPDATE,
DELETE
} from 'admin-on-rest/src/rest/types';
出现以下错误:
Failed to compile.
./node_modules/admin-on-rest/src/util/fetch.js
Module parse failed: Unexpected token (20:24)
You may need an appropriate loader to handle this file type.
| }
|
| return fetch(url, { ...options, headers: requestHeaders })
| .then(response =>
| response.text().then(text => ({
所以,由于我不是 React 程序员,我很想知道如何解决这个问题,以便能够绑定到我的后端以进行进一步测试。
;-)
感谢您的任何提示!