RTK type Error when using injectedEndpoints with openApi - react-redux

I define config file for openApi to create automatically endpoints with types:
const config: ConfigFile = {
schemaFile: 'https://example.com/static/docs/swagger.json',
apiFile: './api/index.ts',
apiImport: 'api',
outputFile: './api/sampleApi.ts',
exportName: 'sampleApi',
hooks: true,
};
export default config;
I used :
"#rtk-query/codegen-openapi": "^1.0.0-alpha.1"
"#reduxjs/toolkit": "^1.7.2",
Then I define an index.tsx that has
export const api = createApi({
baseQuery: axiosBaseQuery({ baseUrl: '' }),
endpoints: () => ({}),
});
and So I generate successfully my sampleApi.tsx file with all of endpoints and types.
like here:
const injectedRtkApi = api.injectEndpoints({
endpoints: (build) => ({
postUsersCollections: build.mutation<
PostUsersCollectionsApiResponse,
PostUsersCollectionsApiArg
>({
query: (queryArg) => ({
url: `/users/collections`,
method: 'POST',
body: queryArg.postCollectionBody,
}),
}),
getUsersCollections: build.query<
GetUsersCollectionsApiResponse,
GetUsersCollectionsApiArg
>({
query: (queryArg) => ({
url: `/users/collections`,
params: { name: queryArg.name },
}),
}),
overrideExisting: false,
});
export const {
usePostUsersCollectionsMutation,
useGetUsersCollectionsQuery
} = injectedRtkApi;
when in a component I use hook function useGetUsersCollectionsQuery as bellow I got an error that TypeError: Cannot read properties of undefined (reading 'subscriptions'). There is no lint typescript error related to typescript in my project.
const { data: collectionData = [] } = useGetUsersCollectionsQuery({});
It's Interesting that this hook called and I see API call in network tab but immediately I got this error. I remove this line and error is disappeared.
And Also for mutation hook I send data within it but I got 400 error. as Below:
const [postCollection, { data: newCollect }] =
usePostUsersCollectionsMutation();
...
const handleCreateItem = async () => {
const response: any = await postCollection({
postCollectionBody: { name: 'sample' },
}); }
Please help me! I really thanks you for taking time.

Finally I resolved it!
I should define reducerPath as this:
export const api = createApi({
reducerPath: 'api', <=== add this and define `api` in reducers
baseQuery: axiosBaseQuery({ baseUrl: '' }),
endpoints: () => ({}),
});

Related

Apollo GraphQL Lambda Handler Cannot read property 'method' of undefined

I am trying to run Apollo GraphQL server inside my AWS lambda. I'm using the library from here. I'm also using CDK to deploy my lambda and the REST API Gateway.
My infrastructure is as follows:
const helloFunction = new NodejsFunction(this, 'lambda', {
entry: path.join(__dirname, "lambda.ts"),
handler: "handler"
});
new LambdaRestApi(this, 'apigw', {
handler: helloFunction,
});
The lambda implementation is as follows:
const typeDefs = `#graphql
type Query {
hello: String
}`;
const resolvers = {
Query: {
hello: () => 'world',
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: true,
})
console.log('###? running lambda')
export const handler = startServerAndCreateLambdaHandler(
server,
handlers.createAPIGatewayProxyEventV2RequestHandler(), {
middleware: [
async (event) => {
console.log('###? received event=' + JSON.stringify(event, null, 2))
return async (result) => {
console.log(("###? result=" + JSON.stringify(result, null, 2)))
result
}
}
]
});
When I POST to my endpoint with the appropriate query I get this error:
{
"statusCode": 400,
"body": "Cannot read property 'method' of undefined"
}
I'm seeing my logging inside the lambda as expected and I can confirm the error is being returned in the 'result' from within startServerAndCreateLambdaHandler(). This code is based on the example for the #as-integrations/aws-lambda library. I don't understand why this is failing.
Need to use:
handlers.createAPIGatewayProxyEventRequestHandler()
Instead of:
handlers.createAPIGatewayProxyEventV2RequestHandler()
So final code is:
export const handler = startServerAndCreateLambdaHandler(
server,
handlers.createAPIGatewayProxyEventRequestHandler(),
{
middleware: [
async (event) => {
console.log('###? received event=' + JSON.stringify(event))
}
]
}
);

Getting Actions must be plain objects error with my redux-observable epic

So I have an api that is using fromFetch like so:
const myApi = () => {
const data$ = fromFetch(url);
return data$;
}
And my epic looks like so:
export const fetchEpic = (action$: any) => {
return action$.pipe(
ofType(Actions.FETCH),
mergeMap(action =>
myApi().pipe(
map(result => {
console.log(result)
return mapTo({ type: Actions.ADD_ITEMS, payload: result });
}),
),
),
);
};
The console.log(result) seems to work without a hitch and no problem. However I am getting the error:
Error: Actions must be plain objects. Use custom middleware for async actions.
As a side note I tried to do some basic testing and did this below and it worked fine so why is the epic above not working?
export const fetchEpic = (action$: any) => {
return action$.pipe(
ofType(Actions.FETCH),
mapTo({ type: Actions.ADD_ITEMS, payload: ['hello'] })
);
};
Made a codesandbox of the above with same error:
https://codesandbox.io/s/agitated-visvesvaraya-b8oun
Inside your map block you should just return the action directly. Your code wraps it with mapTo which is an operator that should only be used inside a pipe method.
So your fetchEpic should be:
export const fetchEpic = (action$: any) => {
return action$.pipe(
ofType(Actions.FETCH),
mergeMap(action =>
myApi().pipe(
map(result => {
console.log(result)
return{ type: Actions.ADD_ITEMS, payload: result };
}),
),
),
);
};
Here is the updated code sandbox: https://codesandbox.io/s/gracious-darkness-9dc9q
Since you're already using TypeScript, I found that many of such errors can actually found by the TypeScript compiler, if you type your epics correctly, e.g.
export const fetchEpic : Epic<YourActionType, YourActionType, YourStateType> = (action$) => { ..

Test for react async action creator - undefined data

I have the following action and test case - when I run this test(jest) - I am seeing TypeError: Cannot read property 'data' of undefined in action creator, not sure what is missing here? I am providing mockData that is expected. is it because there is an async nested here? but i am using `.then but it still fails.
Action creator:
export const getUser = ({
uname,
apiendpoint,
}) => {
const arguments = {};
return async (dispatch) => {
await axiosHelper({ ---> this will return axios.get
arguments,
path: `${apiendpoint}/${uname}`,
dispatch,
}).then(async ({ data, headers }) => { -- getting error at this line.
dispatch({ type: GET_USER, payload: data });
dispatch({ type: GET_NUMBEROFUSERS, payload: headers });
});
};
};
Test:
describe('Get User Action', () => {
let store;
const middlewares = [thunk];
const mockStore = configureStore(middlewares);
beforeEach(() => {
store = mockStore({
data: [],
});
});
afterEach(() => {
fetchMock.reset();
fetchMock.restore();
})
const arguments = {
uname: 'user123',
apiendpoint: 'test',
};
const url = 'https://www.localhost.com/blah/blah';
it('should get a User', () => {
fetchMock
.getOnce(url, {
data: mockData, -->external mock js file with user data {}
headers: {
'content-type': 'application/json'
}
});
const expectedActions = [
{
type: 'GET_USER',
data: mockData
},
{ type: 'GET_NUMBEROFUSERS' }
];
return store.dispatch(actions.getUser(arguments)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
});
});
You are using await AND then on the same function (axiosHelper for example).
This is wrong usage and will lead to many errors of undefined.
You either use a callback-function or a .then() or an await but not 2 or all of them.
I recommend to watch some tutorials/explanations about async/await because it's really important to understand what a Promise is.
What's happening in your cas is that axiosHelper is executed 2 times, because if it's finished the then-part will fire up but at the exactly same time (because it's async) the await finishes and code-execution continues the parent flow. This brings up race-conditions and, as i said, will lead to undefined because you are executing the same logic twice or more.

Apollo breaks when a client is stated in a mutation

I am using this recent feature of adding multiple clients and it is working well so far, but only in this case, the following code breaks when I state the client explicitly in the options of my mutation. I have followed this exact pattern with other components and haven't had any issue.
import { gql } from 'react-apollo';
const networkInterfaceAccounts = createNetworkInterface({
uri: ACCOUNTS_CLIENT_URL,
});
networkInterfaceAccounts.use([authMiddleware]);
const apolloClientAccounts = new ApolloClient({
networkInterface: networkInterfaceAccounts,
reduxRootSelector: state => state.apolloAccounts,
});
export const signupRequestMutation = gql`
mutation signupRequest($username: String!, $fname: String!, $lname: String!) {
signupRequest(username: $username, firstName: $fname, lastName: $lname) {
_id
}
}
`;
export const signupRequestOptions = {
options: () => ({
client: apolloClientAccounts,
}),
props: ({ mutate }) => ({
signupRequest: ({ username, fname, lname }) => {
return mutate({
variables: {
username,
fname,
lname,
},
});
},
}),
};
And the react component looks like this:
export default compose(
graphql(signupRequestMutation, signupRequestOptions),
withRouter,
reduxForm({
form: 'signup',
validate,
}),
)(SignupForm);
Intended outcome:
As with other components, I expect that the mutation works whether I pass client as an option or not.
options: () => ({
client: apolloClientAccounts,
}),
Actual outcome:
I am getting this error:
Uncaught Error: The operation 'signupRequest' wrapping 'withRouter(ReduxForm)' is expecting a variable: 'username' but it was not found in the props passed to 'Apollo(withRouter(ReduxForm))'
After that, I can submit the form.
Version
apollo-client#1.9.1
react-apollo#1.4.15

Why won't VueJS invoke methods from the created() function?

Learning VueJS and trying to do a simple API call on component load to put a list of repos onto my page. When I call and set the this.repos from the created() method, no problem. But if I set it as a method and then call it from this.getRepos nothing happens. No error, nothing. What am I missing about VueJS?
This works:
data: () => ({
msg: 'Github Repos',
ok: 'Im practically giving away these repos',
repos: [],
}),
methods: {
},
async created() {
const repos = await axios.get('https://api.github.com/orgs/octokit/repos');
this.repos = repos.data.map(repo =>
`<div class="box"><a href="${repo.html_url}">
${repo.name}
</div>`,
);
},
This DOES NOT work:
data: () => ({
msg: 'Github Repos',
ok: 'Im practically giving away these repos',
repos: [],
}),
methods: {
getRepos: async () => {
const repos = await axios.get('https://api.github.com/orgs/octokit/repos');
this.repos = repos.data.map(repo =>
`<div class="box"><a href="${repo.html_url}">
${repo.name}
</div>`,
);
},
},
created() {
this.getRepos();
},
Any ideas? Thanks!
It's simply because you used arrow functions here so that this.repos's this is bound to window object. Changing async () => {} to async function() {} will help you overcome it.
See demo
Note that you should not use an arrow function to define a method (e.g. plus: () => this.a++). The reason is arrow functions bind the parent context, so this will not be the Vue instance as you expect and this.a will be undefined.
reference
Another way to do an Axios call with Vue using then() method:
demo
created() {
axios.get('https://api.github.com/orgs/octokit/repos', {
params: {
type: 'all',
},
})
.then((res) => {
console.log('Success Response', res.data);
res.data.forEach((repo) => {
this.repos.push({ name: repo.name, url: repo.html_url, language: repo.language });
});
})
.catch((err) => {
console.log('Error', err);
});
},

Resources