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
Related
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 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.
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.
I have the following code, I am using React:
// post-post
const queryDatabase = (obj, endpoint) => {
console.log(obj);
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(obj)
};
console.log(endpoint);
fetch(endpoint, requestOptions)
.then(data => {return Promise.resolve(data)}
);
}
export {queryDatabase};
For some reason console.log(endpoint) prints the endpoint that I am passing in, e.g. "/users", "/profile" etc. However, fetch is trying to send to http://localhost:3000/users so when I try to manually pass in an endpoint I get an error about trying to post to http://localhost/http://localhost/users.
Where is fetch getting this default http://localhost:3000 value?
It's only doing this for POST requests.
The only environment variables are the following:
REACT_APP_AUTH0_REDIRECT_URI=http://localhost:3000
REACT_API_SERVER_URL=http://api.localhost
PORT=3000
I also have some other environment variables for Auth0, is Auth0 doing this? I've removed these variables for testing and still nothing.
The answer is to use the Request object and pass that through to fetch:
const requestOptions = new Request(serverUrl + endpoint, {
method: 'POST',
body: JSON.stringify(obj),
headers: new Headers({
'Content-Type': 'application/json'
})
});
Why bother... use axios or something else, fetch sucks.
EDIT:
Apparently not a problem with fetch. Whatever the case this is the fix.