How to transform GQL schema on its generating? [NestJS] - graphql

I want to apply prefixes to all types, mutations, etc. in GQL schema generated. Here is my config factory:
useFactory: (configService: ConfigService) => ({
autoSchemaFile: 'schema.graphql',
sortSchema: true,
// eslint-disable-next-line #typescript-eslint/explicit-function-return-type
transformSchema: schema => wrapSchema({
schema,
transforms: [
new RenameTypes(name => `New${name}`),
new RenameObjectFields((_, fieldName) => `new_${fieldName}`),
new RenameInterfaceFields((_, fieldName) => `new_${fieldName}`),
new RenameInputObjectFields((_, fieldName) => `new_${fieldName}`),
],
}),
playground: configService.get<string>('NODE_ENV') === 'development',
context: ({ req, res }): { req: Request; res: Response } => ({
req,
res,
}),
tracing: configService.get<string>('NODE_ENV') === 'development',
}),
wrapSchema works fine but as a result I'm still getting old schema... It seems like transformSchema is not working at all. How to fix it?

So, after exploring the source code of #nestjs/graphql I found out that in order to make transformSchema option work I have to set transformAutoSchemaFile: true because I use autoSchemaFile.

Related

RTK type Error when using injectedEndpoints with openApi

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: () => ({}),
});

How can i set my ApolloServer to open a graphql playground instead of the apollographql sandbox by default?

My question is how can i set this graphql playground extension as my default playground instead of using the default sandbox when i visited http://hocalhost/port/graphql. Is there any option that i can set during the creation of the ApolloServer instance that can configure that?.
...
const apolloServer = new ApolloServer({
schema: await buildSchema({
validate: false,
resolvers: [HelloResolver, UserResolver],
}),
context: ({ req, res }) => ({ em: orm.em, req, res }),
});
await apolloServer.start();
apolloServer.applyMiddleware({ app });
....
Use the GraphQL Playground plugin and provide it to your Apollo Server constructor. For more info checkout Apollo Docs.
import {
ApolloServerPluginLandingPageGraphQLPlayground
} from "apollo-server-core";
const apolloServer = new ApolloServer({
...
plugins: [
ApolloServerPluginLandingPageGraphQLPlayground(),
],
});

Can I access request headers in my graphql query, in nestjs?

I am trying to access the ip-address of the user in the query of graphql. But I cannot reach any header information. How can I access the context I am creating in my factory, inside of my graphql requests?
// app.module.ts
...
#Module({
imports: [
ConfigModule,
GraphQLModule.forRootAsync({
imports: [
LanguageModule,
SearchModule],
inject: [ConfigService],
useFactory: () => ({
autoSchemaFile: 'schema.gql',
debug: true,
fieldResolverEnhancers: ['guards'],
formatError: (error: GraphQLError): GraphQLFormattedError => {
return error.originalError instanceof BaseException
? error.originalError.serialize()
: error;
},
context: ({ req }): object => {
console.log("req.ip: ", req.ip); // Here I have the ip
return { req };
},
}),
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
// search.resolver.ts
...
#Resolver(() => Search)
export class SearchResolver {
constructor(private readonly service: service) {}
#Query(() => Search)
async search(#Args() args: SearchArgs): Promise<Search> {
// I want the ip here, I want to send it as an argument into the query function below
const response = await this.service.query(args.query, {
language: args.language,
});
return response;
}
}
According to this thread resolver context parameter should contain req but it depends [on configuration].
Resolvers typically takes (parent, args, context, info) arguments - check if context is defined in yours.

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$) => { ..

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

Resources