Here's my Apollo Server definition.
const server = new ApolloServer({
schema,
context: (async ({ req }) => {
console.log(req);
return {};
}),
csrfPrevention: true,
cache: 'bounded',
plugins: [
ApolloServerPluginDrainHttpServer({ httpServer }),
ApolloServerPluginLandingPageLocalDefault({ embed: true }),
],
});
As we can see that auth property does exists in the req object but somehow when I tried to get the value, an error thrown Property 'auth' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>' How can I retrieve the auth property?
<ref *2> IncomingMessage {
...,
auth: { sub: '1234567890', name: 'John Doe', iat: 1516239022 },
body: { query: 'query Query() {\n }\n}\n' },
_body: true,
length: undefined,
[Symbol(kCapture)]: false,
[Symbol(RequestTimeout)]: undefined
}
after a little bit try and error, I can solve this issue by cast the context request to express-jwt.Request type as the code shown below,
const server = new ApolloServer({
schema,
context: (({ req }: { req: Request }) => {
console.log(req.auth);
return {};
}),
csrfPrevention: true,
cache: 'bounded',
plugins: [
ApolloServerPluginDrainHttpServer({ httpServer }),
ApolloServerPluginLandingPageLocalDefault({ embed: true }),
],
});
Related
i am using Redux-toolkit-query to fetch data from server. Now i want to call my query on button click,not automatically.I tried this but it's not working.
const { data, refetch } = useGetBuisnessAreasQuery({
enable: false,
refetchOnWindowFocus: false,
manual: true,
refetchOnReconnect: false,
});
You have to use the lazy query hook:
const [ trigger, { data } ] = api.endpoints.getBuisnessAreas.useLazyQuery()
const onClick = () => {
trigger()
}
This is how I did it, it's only cleaner:
in feature/service.ts:
export const authenticationApi = createApi({
reducerPath: 'myApi',
baseQuery: fetchBaseQuery({ baseUrl: baseUrl }),
endpoints: builder => ({
attemptLogin: builder.query({
query: (credentials) => ({
url: '/',
body: JSON.stringify(body)
})
})
})
})
export const { useLazyAttemptLoginQuery } = authenticationApi
and using it:
const [getAuthenticated, { data, isLoading, error }] = useLazyAttemptLoginQuery()
I want to process the data that I get from the request in the slice.
Because not all slices are async (but work with the same data), transformResponse is not suitable.
Is there anything you can suggest?
My code example:
Some RTK Query
export const currencyApi = createApi({
reducerPath: 'currencyApi',
baseQuery: fetchBaseQuery({ baseUrl: 'https://api.apilayer.com/exchangerates_data' }),
endpoints: (build) => ({
fetchCurrencyRates: build.query<IApiResponse, string>({
query: (currency) => ({
url: '/latest',
params: {
base: currency
},
headers: {
apikey: *SomeApiKey*
}
})
})
})
})
Slice where I want to use data from RTK requests
const initialState: ICurrencyState = {
currencyRates: {},
availableCurrencyOptions: [],
fromCurrency: '',
toCurrency: '',
exchangeRate: 0,
error: null
}
export const currencySlice = createSlice({
name: 'currency',
initialState,
reducers: {
//
}
})
Use Hooks in Components
You can send the received data to the slice via useEffect. Something like this:
const { data } = useFetchCurrencyRatesQuery();
useEffect(() => {
if (data !== undefined) {
dispatch(...)
}
}, [data])
#Injectable()
export class GqlThrottlerGuard extends ThrottlerGuard {
getRequestResponse(context: ExecutionContext) {
const gqlCtx = GqlExecutionContext.create(context);
const ctx = gqlCtx.getContext();
return { req: ctx.req, res: ctx.res };
}
}
Here I am getting only req from ctx, res is undefined. I am using GraphQL with express in nestjs.
This is how my context object looks like before creating a GqlExecutionContext:
ExecutionContextHost {
args: [
undefined,
{ id: 2 },
{ req: [IncomingMessage] },
{
fieldName: 'user',
fieldNodes: [Array],
returnType: User!,
parentType: Query,
path: [Object],
schema: [GraphQLSchema],
fragments: [Object: null prototype] {},
rootValue: undefined,
operation: [Object],
variableValues: {},
cacheControl: [Object]
}
],
constructorRef: [class UsersResolver],
handler: [Function: findOne],
contextType: 'graphql'
}
Error:
[Nest] 30284 - 08/01/2022, 12:54:25 am ERROR [ExceptionsHandler] Cannot read property 'ip' of undefined
TypeError: Cannot read property 'ip' of undefined
at ThrottlerGuard.getTracker (C:\Users\Mahesh\OneDrive\Desktop\graphql-server\node_modules\#nestjs\throttler\dist\throttler.guard.js:95:16)
In my case, I got the following error message
cannot read property 'header' of undefined
I think the main problem comes from the ctx.res which is undefined.
To resolved the problem I used the following code:
ctx.req.res
In your case it should be:
#Injectable()
export class GqlThrottlerGuard extends ThrottlerGuard {
getRequestResponse(context: ExecutionContext) {
const gqlCtx = GqlExecutionContext.create(context);
const ctx = gqlCtx.getContext();
return { req: ctx.req, res: ctx.req.res };
}
}
I have added the req, res to the context in GraphQLModule.forRoot() So after creating Graphql execution context I am able to get the required data in the return statement { req: ctx.req, res: ctx.res }.
GraphQLModule.forRoot({
autoSchemaFile: 'src/graphql-schema.gql',
context: ({ req, res }) => ({ req, res }),
}),
I have graphql config:
export const graphQLConfig: GqlModuleAsyncOptions = {
imports: [ConfigModule],
useFactory: (configService: ConfigService) => ({
autoSchemaFile: 'schema.graphql',
cacheControl: {
defaultMaxAge: 60,
stripFormattedExtensions: false,
calculateHttpHeaders: true.
},
...
}),
inject: [ConfigService],
}
And now I want to cache my response from resolver sending large amount of data:
#Query(() => [ConvertRateType])
async getRates(
#Args('input') input: GetConvertRatesInput,
): Promise<ConvertRateType[]> {
const rates = await this._ratesService.getRates(input)
return rates
}
How can I do this using #nestjs/graphql? I'm using redis as a storage.
Hello I'm new to GraphQl and to Apollo Server.
I would like to implement authentication on my project.
But
For some reason, I can't seem to set context on my resolvers in apollo server.
Here's my index
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => {
const userId = jwtDecode(req.headers.authorization)
return userId.sub
}
})
And my query
Query: {
users: async (parent, args, context) => {
try {
console.log(context)
return await getUsers(context)
} catch (err) {
console.log(err)
throw new Error(err.message)
}
}
When I try to output the context the result is always like this...
{ injector:
Injector {
options:
{ name: 'index.ts_8346047369535445_SESSION',
injectorScope: 'SESSION',
hooks: [Array],
children: [] },
_classMap: Map {},
_factoryMap: Map {},
_applicationScopeInstanceMap:
Map {
Symbol(ModuleConfig.index.ts_8346047369535445) => undefined,
[Function] => undefined },
_sessionScopeInstanceMap: Map { [Function: ModuleSessionInfo] => [ModuleSessionInfo] },
_applicationScopeServiceIdentifiers:
[ Symbol(ModuleConfig.index.ts_8346047369535445), [Function] ],
_requestScopeServiceIdentifiers: [],
_sessionScopeServiceIdentifiers: [ [Function: ModuleSessionInfo] ],
_hookServiceIdentifiersMap: Map {},
_name: 'index.ts_8346047369535445_SESSION',
_injectorScope: 'SESSION',
_defaultProviderScope: 'SESSION',
........
What's returned inside the context function should always be an object. So you would do something like
context: ({ req }) => {
const { sub } = jwtDecode(req.headers.authorization)
return {
sub,
}
}
and then access the value inside the resolver by calling context.sub.
However, if you're using GraphQL Modules to create your schema, you should follow the library's documentation for configuring your context on a per-module basis.