I set extraOptions in my endpoint like so :
const myApi = api.injectEndpoints({
endpoints: builder => ({
changePassowrd: builder.mutation({
query: (data) => ({
url: `${Config.BASE_URL}/users/${data.userId}`,
method: 'PATCH',
body: data,
}),
extraOptions: () => ({
myOption: 'Test Option',
}),
}),
})
})
And I try to read extraOptions in prepareHeaders like so:
const baseQuery = fetchBaseQuery({
baseUrl: Config.BASE_URL,
prepareHeaders: (headers, {getState, extra}) => {
console.log('Extra Stuff', extra); // undefined
return headers;
},
});
But I'm always getting undefined in the console after triggering the mutation, why is that? Am I using it wrong?
That's redux-thunk's extra, not the endpoint's extraOptions. It seems like fetchBaseQuery generally does not make use of extraOption - a pull request integrating that where necessary is highly welcome.
Related
I have a POST request which returns a 302 when successful. I need to get the location response header which holds the url I'll need to redirect to. Currently I have this:
accountLogin: builder.mutation<any, any>({
query: (body) => ({
url: `/accounts/login`,
method: 'POST',
body,
responseHandler: (response) => {
console.log(response, response.headers);
return response.text();
},
}),
}),
If I look in the network tab of my browser the 302 is there, as is the location header with the proper URL. But the 'console.log' in responseHandler shows no headers. I can't find much about this in the documentation -- what am I missing?
to access status code you can use validateStatus something like this:
import { createApi, fetchBaseQuery } from '#reduxjs/toolkit/query'
export const customApi = createApi({
// Set the baseUrl for every endpoint below
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
endpoints: (builder) => ({
getUsers: builder.query({
query: () => ({
url: `users`,
// Example: we have a backend API always returns a 200,
// but sets an `isError` property when there is an error.
validateStatus: (response, result) =>
response.status === 200 && !result.isError,
}),
}),
}),
})
or use transformResponse
transformResponse: (response, meta, arg) =>
response.some.deeply.nested.collection
i started implementing RTK QUERYnow i am facing one issue , i have an API,the API returns user Settings. Now from API if the there is data related to user it returns success=1 otherwise success=0 , but in both cases it returns response status 200. Now i want to show error to user if sucess=0 and set the set the error in the RTk Error object. How can i implement that.
import { apiSlice } from "../../services/ApiSlice";
import * as URL from "../Urls";
export const userSlice = apiSlice.injectEndpoints({
endpoints: (builder) => ({
getUserSettings: builder.mutation({
query: (body) => ({
url: URL.GET_SETTINGS,
method: "POST",
body: body,
responseHandler: (response) => response.json(),
validateStatus: (response, result) =>
response.status === 200 ? result : "error in fetching data",
}),
transformResponse: (response) => {
console.log({ response });
if (response.success === 0) return "Error in fetching data";
},
providesTags: (result, error, arg) => {
if (result) {
console.log(result);
return [...result.ids.map((id) => ({ type: "users", id })), "users"];
} else return ["users"];
},
}),
}),
});
export const { useGetUserSettingMutation } = userSlice;
I'm using RTKQuery to fetch data as following:
export const productsApi = createApi({
reducerPath: 'productsApi',
baseQuery: fetchBaseQuery({
baseUrl: BASE_URL,
prepareHeaders,
}),
tagTypes: ['Products'],
keepUnusedDataFor: 8600,
endpoints: builder => ({
getProperties: builder.query<IProduct[], IParams>({
query: params => ({ url: 'products', params: { per_page: 40, ...params } }),
transformResponse: ({ data }: { data: IProduct[] }) => data,
providesTags: ['Products'],
}),
});
I am relatively new to Redux Toolkit and started it using directly before using any of Redux. From the ReduxToolkit documentation, I'm finding 2 ways to catch and put actions on the backend.
Using Async thunk.
Middleware
I tried using the code as follows with the Middleware approach:
export const rtkQueryErrorLogger: Middleware = (api: MiddlewareAPI) => next => action => {
if (isRejected(action)) {
console.log(action);
}
return next(action);
}
But this does not catch the 40x/50x errors. What should be the way to handle this?
The purpose is to say send logs to the server upon catching these errors with meta-information. I was following: https://redux-toolkit.js.org/rtk-query/usage/error-handling#handling-errors-at-a-macro-level as a reference.
how to disable prepareHeaders on specific endpoint?, for example, i dont need authorization header on login or register endpoint, but on some endpoint i need authorization headers.
export const backendService = createApi({
reducerPath: 'backend',
baseQuery: fetchBaseQuery({
baseUrl: `${Endpoint}`,
prepareHeaders: (headers, {getState}) => {
const token = getState().auth.token;
if (token) {
headers.set('authorization', `Bearer ${token}`);
}
headers.set('Access-Control-Allow-Origin', '*');
return headers;
},
}),
tagTypes: ['Question', 'Questions'],
endpoints: build => ({
registerUser: build.mutation({ <------ skip prepareHeaders in register
query: body => ({
url: 'auth/local/register',
method: 'POST',
body,
}),
}),
login: build.mutation({ <------- skip prepareHeaders on login
query: body => ({
url: 'auth/local',
method: 'POST',
body,
}),
}),
getCategories: build.query({ <------ apply prepareHeaders
query: () => {
return {
url: 'categories'
};
},
}),
}),
});
The current beta for RTK 1.7 passes the endpointname to prepareHeaders, so if you try that you should be able to work around that.
The BaseQueryApi and prepareheaders args now include fields for endpoint name, type to indicate if it's a query or mutation, and forced to indicate a re-fetch even if there was already a cache entry. These can be used to help determine headers like Cache-Control: no-cache.
There is such kind of code that I have:
const mapStateToProps = (state, ownProps) => ({
historyData: getHistoryForSavedVariants(state)[ownProps.savedVariant.variantId],
isHistoryLoading: getHistoryLoading(state),
})
const mapDispatchToProps = (dispatch, ownProps) => ({
loadData: () => {
-----> dispatch(loadHistoryForSavedVariant(ownProps.savedVariant))
},
})
export default connect(mapStateToProps, mapDispatchToProps)(HistoryButton)
In another file loadHistoryForSavedVariant is the following:
export const loadHistoryForSavedVariant = (savedVariant) => {
return (dispatch) => {
dispatch({ type: REQUEST_HISTORY })
const url = `/api/saved_variant/${savedVariant.variantId}/saved_variant_history`
new HttpRequestHelper(url,
(responseJson) => {
dispatch({ type: RECEIVE_HISTORY })
dispatch({ type: RECEIVE_DATA, updatesById: responseJson })
},
(e) => {
dispatch({ type: RECEIVE_HISTORY })
dispatch({ type: RECEIVE_DATA, error: e.message, updatesById: {} })
},
).get({ xpos: savedVariant.xpos, ref: savedVariant.ref, alt: savedVariant.alt, familyGuid: savedVariant.familyGuids[0] })
}
}
So, as can be seen dispatch ultimately gets a function - (dispatch) => {...} and not an action. Why? I don't understand how that works. On Redux official webpage I see everwhere that dispatch gets an action and not a function, so I am confused. The code is, of course, working fine, I am just interested in this particular mechanism, in whats happening here.
That is a "thunk function". Thunks are a Redux middleware that allow you to pass functions into dispatch(), which is useful for writing async logic separate from your components.
For more details, see these Redux tutorials:
https://redux.js.org/tutorials/fundamentals/part-6-async-logic
https://redux.js.org/tutorials/essentials/part-5-async-logic