在 saga 中使用自定义 restClient
Using custom restClient in saga
我想 select 我的 API (api/locales) 中的所有语言环境。
我的问题是 yield call() return 函数作为计划字符串(是的,是纯字符串),我不知道为什么!
也许我错过了 yield + call + restClient 响应的东西?? =\
我的 Saga 文件如下所示:
import types from './types';
import actions from './actions';
import { call, put, takeEvery } from 'redux-saga/effects';
import restClient from './../../restClient';
function* getLocalesSaga() {
try {
yield put({type: types.GET_LOCALES_LOADING});
let locales;
locales = yield call(restClient, 'GET', 'locales');
console.log(locales); // this show the function string!!!
if (!locales.data) {
throw new Error('REST response must contain a data key');
}
yield put( {type: types.LOCALES_RECEIVED, locales } )
} catch (error) {
console.log(error);
yield put({type: types.GET_LOCALES_FAILURE, error})
}
}
export default function* localesSaga() {
yield [
takeEvery(types.GET_LOCALES, getLocalesSaga),
takeEvery(types.GET_LOCALES_LOADING, actions.loadingLocales),
takeEvery(types.LOCALES_RECEIVED, actions.localesReceived),
takeEvery(types.GET_LOCALES_FAILURE, actions.failedLocales),
];
}
console.log 输出为:
ƒ (type, resource, params) {
if (type === __WEBPACK_IMPORTED_MODULE_0_admin_on_rest__["GET_MANY"]) {
return Promise.all(params.ids.map(function (id) {
return httpClient(apiUrl + '/' +…
浏览器网络选项卡中没有请求。
除了 console.log.
之外,控制台中没有 JS 错误
我在 Admin 组件上使用 customSagas={customsSagas} 注册了 saga。
当我使用 fetch() 函数时它起作用了!
我想使用我的 restClient,其中包括身份验证令牌以及请求和响应的所有逻辑。
restClient 是自定义的,这是代码:
import {
GET_LIST,
GET_ONE,
GET_MANY,
GET_MANY_REFERENCE,
CREATE,
UPDATE,
DELETE,
fetchUtils
} from 'admin-on-rest';
const { queryParameters, fetchJson } = fetchUtils;
const apiUrl = process.env.REACT_APP_API_PATH;
const httpClient = (url, options = {}) => {
if (!options.headers) {
options.headers = new Headers({ Accept: 'application/json' });
}
const token = localStorage.getItem('token');
options.headers.set('Authorization', `Bearer ${token}`);
return fetchJson(url, options);
}
/**
* 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 () => {
/**
* @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 = {
...params.filter,
sort: field,
order: order,
page: page,
per_page: perPage,
};
url = `${apiUrl}/${resource}?${queryParameters(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 = {
...params.filter,
[params.target]: params.id,
_sort: field,
_order: order,
_start: (page - 1) * perPage,
_end: page * perPage,
};
url = `${apiUrl}/${resource}?${queryParameters(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:
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 {
// change the primary key to uuid
data: json.data.map(resource => resource = { ...resource, id: resource.uuid }),
total: parseInt(headers.get('x-total-count').split('/').pop(), 10),
};
case UPDATE:
case DELETE:
case GET_ONE:
return { data: json, id: json.uuid };
case CREATE:
return { data: { ...params.data, id: json.uuid } };
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) => {
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));
};
};
任何人都可以在这里提供帮助并告诉我为什么 restClient returned 作为字符串而不是 returning json?
这不是 GET_LIST 也不是 GET_ONE 请求。这只是一个普通的 GET 请求。
我尝试使用 GET_ONE 和 GET_LIST 但我仍然得到作为函数纯字符串的响应。
编辑&解决方案:
感谢@Gildas,对于 GET 请求使用 fetch 而不是 restClient 更清楚。 restClient 仅用于 <resource />
并且文档不是很清楚。
此外,当我在我的主要 saga 函数中使用 put
时,动作创建者是无用的。
我的提取看起来像这样并且有效:
function getLocales() {
return fetch(process.env.REACT_APP_API_PATH + '/locales', { method: 'GET' })
.then(response => (
Promise.resolve(response)
))
.then(response => (
response.json()
))
.catch((e) => {
console.error(e);
});
}
当我这样称呼它时:
const { languages, currentLocale } = yield call(getLocales);
在此先感谢您。
狮子座
这部分真的很奇怪,尽管您在 getLocalesSaga 中put
对动作创建者进行了绑定,但您似乎将其绑定为 sagas:
export default function* localesSaga() {
yield [
takeEvery(types.GET_LOCALES, getLocalesSaga),
takeEvery(types.GET_LOCALES_LOADING, actions.loadingLocales),
takeEvery(types.LOCALES_RECEIVED, actions.localesReceived),
takeEvery(types.GET_LOCALES_FAILURE, actions.failedLocales),
];
}
此外,restClient
不是 fetch
。 GET
不是它识别的类型(参见 documentation)。您不应该将 restClient
用于任何不是静态管理员术语中的资源的内容。在这里,你确实应该使用 fetch
.
这可能应该重写为:
import types from './types';
import actions from './actions';
import { call, put, takeEvery } from 'redux-saga/effects';
import restClient from './../../restClient';
function fetchLocales() {
return fetch(...);
}
function* getLocalesSaga() {
try {
yield put(actions.loadingLocales());
let locales;
locales = yield call(fetchLocales);
console.log(locales); // this show the function string!!!
if (!locales.data) {
throw new Error('REST response must contain a data key');
}
yield put(actions.localesReceived(locales))
} catch (error) {
console.log(error);
yield put(actions.failedLocales(error))
}
}
export default function* localesSaga() {
yield takeEvery(types.GET_LOCALES, getLocalesSaga);
}
我想 select 我的 API (api/locales) 中的所有语言环境。
我的问题是 yield call() return 函数作为计划字符串(是的,是纯字符串),我不知道为什么!
也许我错过了 yield + call + restClient 响应的东西?? =\
我的 Saga 文件如下所示:
import types from './types';
import actions from './actions';
import { call, put, takeEvery } from 'redux-saga/effects';
import restClient from './../../restClient';
function* getLocalesSaga() {
try {
yield put({type: types.GET_LOCALES_LOADING});
let locales;
locales = yield call(restClient, 'GET', 'locales');
console.log(locales); // this show the function string!!!
if (!locales.data) {
throw new Error('REST response must contain a data key');
}
yield put( {type: types.LOCALES_RECEIVED, locales } )
} catch (error) {
console.log(error);
yield put({type: types.GET_LOCALES_FAILURE, error})
}
}
export default function* localesSaga() {
yield [
takeEvery(types.GET_LOCALES, getLocalesSaga),
takeEvery(types.GET_LOCALES_LOADING, actions.loadingLocales),
takeEvery(types.LOCALES_RECEIVED, actions.localesReceived),
takeEvery(types.GET_LOCALES_FAILURE, actions.failedLocales),
];
}
console.log 输出为:
ƒ (type, resource, params) {
if (type === __WEBPACK_IMPORTED_MODULE_0_admin_on_rest__["GET_MANY"]) {
return Promise.all(params.ids.map(function (id) {
return httpClient(apiUrl + '/' +…
浏览器网络选项卡中没有请求。 除了 console.log.
之外,控制台中没有 JS 错误我在 Admin 组件上使用 customSagas={customsSagas} 注册了 saga。
当我使用 fetch() 函数时它起作用了!
我想使用我的 restClient,其中包括身份验证令牌以及请求和响应的所有逻辑。 restClient 是自定义的,这是代码:
import {
GET_LIST,
GET_ONE,
GET_MANY,
GET_MANY_REFERENCE,
CREATE,
UPDATE,
DELETE,
fetchUtils
} from 'admin-on-rest';
const { queryParameters, fetchJson } = fetchUtils;
const apiUrl = process.env.REACT_APP_API_PATH;
const httpClient = (url, options = {}) => {
if (!options.headers) {
options.headers = new Headers({ Accept: 'application/json' });
}
const token = localStorage.getItem('token');
options.headers.set('Authorization', `Bearer ${token}`);
return fetchJson(url, options);
}
/**
* 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 () => {
/**
* @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 = {
...params.filter,
sort: field,
order: order,
page: page,
per_page: perPage,
};
url = `${apiUrl}/${resource}?${queryParameters(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 = {
...params.filter,
[params.target]: params.id,
_sort: field,
_order: order,
_start: (page - 1) * perPage,
_end: page * perPage,
};
url = `${apiUrl}/${resource}?${queryParameters(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:
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 {
// change the primary key to uuid
data: json.data.map(resource => resource = { ...resource, id: resource.uuid }),
total: parseInt(headers.get('x-total-count').split('/').pop(), 10),
};
case UPDATE:
case DELETE:
case GET_ONE:
return { data: json, id: json.uuid };
case CREATE:
return { data: { ...params.data, id: json.uuid } };
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) => {
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));
};
};
任何人都可以在这里提供帮助并告诉我为什么 restClient returned 作为字符串而不是 returning json?
这不是 GET_LIST 也不是 GET_ONE 请求。这只是一个普通的 GET 请求。 我尝试使用 GET_ONE 和 GET_LIST 但我仍然得到作为函数纯字符串的响应。
编辑&解决方案:
感谢@Gildas,对于 GET 请求使用 fetch 而不是 restClient 更清楚。 restClient 仅用于 <resource />
并且文档不是很清楚。
此外,当我在我的主要 saga 函数中使用 put
时,动作创建者是无用的。
我的提取看起来像这样并且有效:
function getLocales() {
return fetch(process.env.REACT_APP_API_PATH + '/locales', { method: 'GET' })
.then(response => (
Promise.resolve(response)
))
.then(response => (
response.json()
))
.catch((e) => {
console.error(e);
});
}
当我这样称呼它时:
const { languages, currentLocale } = yield call(getLocales);
在此先感谢您。 狮子座
这部分真的很奇怪,尽管您在 getLocalesSaga 中put
对动作创建者进行了绑定,但您似乎将其绑定为 sagas:
export default function* localesSaga() {
yield [
takeEvery(types.GET_LOCALES, getLocalesSaga),
takeEvery(types.GET_LOCALES_LOADING, actions.loadingLocales),
takeEvery(types.LOCALES_RECEIVED, actions.localesReceived),
takeEvery(types.GET_LOCALES_FAILURE, actions.failedLocales),
];
}
此外,restClient
不是 fetch
。 GET
不是它识别的类型(参见 documentation)。您不应该将 restClient
用于任何不是静态管理员术语中的资源的内容。在这里,你确实应该使用 fetch
.
这可能应该重写为:
import types from './types';
import actions from './actions';
import { call, put, takeEvery } from 'redux-saga/effects';
import restClient from './../../restClient';
function fetchLocales() {
return fetch(...);
}
function* getLocalesSaga() {
try {
yield put(actions.loadingLocales());
let locales;
locales = yield call(fetchLocales);
console.log(locales); // this show the function string!!!
if (!locales.data) {
throw new Error('REST response must contain a data key');
}
yield put(actions.localesReceived(locales))
} catch (error) {
console.log(error);
yield put(actions.failedLocales(error))
}
}
export default function* localesSaga() {
yield takeEvery(types.GET_LOCALES, getLocalesSaga);
}