最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

reactjs - Data from the request object is not passing into the graphql context - Stack Overflow

programmeradmin0浏览0评论

I am trying to pass my userId and isAuth as req.userId and req.isAuth for my createPost resolver. Unfortunately, I am unable to pass my properties into the resolver.

// types/express.d.ts
import { Request } from 'express';

declare global {
  namespace Express {
    interface Request {
      isAuth?: boolean;
      userId?: string;
    }
  }
}

// middleware/auth.ts
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';

export const Auth = async (req: Request, res: Response, next: NextFunction) => {
  try {
    const authHeader = req.get('Authorization');
    if (!authHeader) {
      req.isAuth = false;
      return next();
    }

    const token = authHeader.split(' ')[1];
    const decodedToken = jwt.verify(token, 'your-secret') as { userId: string };
    
    req.isAuth = true;
    req.userId = decodedToken.userId;
    next();
  } catch (err) {
    req.isAuth = false;
    next();
  }
};

// app.ts
import express from 'express';
import { createHandler } from 'graphql-http/lib/use/express';
import { Auth } from './middleware/auth';

const app = express();

// Apply auth middleware
app.use(Auth);

// GraphQL handler
app.use(
  '/graphql',
  createHandler({
    schema: yourSchema,
    rootValue: yourResolvers,
    context: (req) => ({
      isAuth: req.isAuth,  // This is undefined
      userId: req.userId   // This is undefined
    })
  })
);

// Resolver
const resolvers = {
  createPost: async ({ postInput, context }) => {
    console.log('Context:', context); // Shows undefined values
    if (!context.isAuth) {
      throw new Error('Not authenticated');
    }
    // ... rest of the resolver
  }
};

I am unable to figure out why my properties are logging out the values in my auth middleware however when being passed to the resolver function via context obj it is logging undefined. I want to know why it happens likes so and how can I better deal with it.

For more context about this project here is my repository:

I am trying to pass my userId and isAuth as req.userId and req.isAuth for my createPost resolver. Unfortunately, I am unable to pass my properties into the resolver.

// types/express.d.ts
import { Request } from 'express';

declare global {
  namespace Express {
    interface Request {
      isAuth?: boolean;
      userId?: string;
    }
  }
}

// middleware/auth.ts
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';

export const Auth = async (req: Request, res: Response, next: NextFunction) => {
  try {
    const authHeader = req.get('Authorization');
    if (!authHeader) {
      req.isAuth = false;
      return next();
    }

    const token = authHeader.split(' ')[1];
    const decodedToken = jwt.verify(token, 'your-secret') as { userId: string };
    
    req.isAuth = true;
    req.userId = decodedToken.userId;
    next();
  } catch (err) {
    req.isAuth = false;
    next();
  }
};

// app.ts
import express from 'express';
import { createHandler } from 'graphql-http/lib/use/express';
import { Auth } from './middleware/auth';

const app = express();

// Apply auth middleware
app.use(Auth);

// GraphQL handler
app.use(
  '/graphql',
  createHandler({
    schema: yourSchema,
    rootValue: yourResolvers,
    context: (req) => ({
      isAuth: req.isAuth,  // This is undefined
      userId: req.userId   // This is undefined
    })
  })
);

// Resolver
const resolvers = {
  createPost: async ({ postInput, context }) => {
    console.log('Context:', context); // Shows undefined values
    if (!context.isAuth) {
      throw new Error('Not authenticated');
    }
    // ... rest of the resolver
  }
};

I am unable to figure out why my properties are logging out the values in my auth middleware however when being passed to the resolver function via context obj it is logging undefined. I want to know why it happens likes so and how can I better deal with it.

For more context about this project here is my repository: https://github/Mr-Unfettable/node-shop/tree/bugfixes

Share Improve this question edited Mar 29 at 3:39 Mr.Unfettable asked Mar 28 at 15:34 Mr.UnfettableMr.Unfettable 918 bronze badges 3
  • 1 That's a lot of code. Can you narrow it down to a minimal reproducible example? – Mureinik Commented Mar 28 at 18:45
  • I have edited the post to zoom in more on the part where the problem is happening. I have done my best to make it straight forward. Please feel free to run the project locally to understand the implementation of the query logic on my frontend. – Mr.Unfettable Commented Mar 29 at 3:42
  • @Mureinik Thanks for the idea to minimize my problem to smaller example. I was not focusing on the main problem rather than the entire code which daunting. Well I can take some rest now its been couple of days. – Mr.Unfettable Commented Mar 29 at 4:37
Add a comment  | 

1 Answer 1

Reset to default 0

Solution: Auth Context Not Being Passed to GraphQL Resolvers with graphql-http

I encountered an issue where my Express authentication middleware wasn't properly passing authentication data (isAuth and userId) to my GraphQL resolvers when using the graphql-http package. After debugging, I discovered the problem was related to inconsistent resolver signature patterns.

The Problem My auth middleware worked correctly and added properties to the request object:

// middleware/auth.ts
export const Auth = async (req: Request, res: Response, next: NextFunction) => {
  try {
    const authHeader = req.get('Authorization');
    if (!authHeader) {
      req.isAuth = false;
      return next();
    }

    const token = authHeader.split(' ')[1];
    const decodedToken = jwt.verify(token, 'your-secret') as { userId: string };
    
    req.isAuth = true;
    req.userId = decodedToken.userId;
    next();
  } catch (err) {
    req.isAuth = false;
    next();
  }
};

And my GraphQL server setup correctly passed these properties to the context:

app.use(
  '/graphql',
  createHandler({
    schema,
    rootValue: resolver,
    context: (request) => {
      const req = request.raw;
      return {
        isAuth: req.isAuth,
        userId: req.userId,
      };
    },
    // ...
  })
);

However, in my resolver, the context was always undefined:

createPost: async (parent: any, { postInput }: { postInput: PostInputData }, context: any, info: any) => {
  console.log('context:', context); // undefined
  console.log('isAuth:', context.isAuth); // Cannot read property 'isAuth' of undefined
  // ...
}

The Solution The issue was that I was using inconsistent resolver signature patterns across my resolvers. My other resolvers were using a different pattern:

// This pattern works
createUser: async ({ userInput }: { userInput: SignUpInputData }) => { ... }
login: async ({ loginInput }: { loginInput: LoginInputData }) => { ... }

// But my createPost resolver used a different pattern
createPost: async (parent: any, { postInput }: { postInput: PostInputData }, context: any, info: any) => { ... }

The solution was to make the createPost resolver signature consistent with my other resolvers:

// Changed to match the pattern of other resolvers
createPost: async ({ postInput }, context) => {
  console.log('context:', context); // Now shows the context object
  console.log('isAuth:', context.isAuth); // Now shows the auth state

  if (!context.isAuth) {
    throw new GraphQLError('Not authenticated!', {
      extensions: {
        statusCode: 401,
      },
    });
  }
  
  // Rest of the resolver...
}

Why This Works

With graphql-http, the way arguments are passed to resolvers depends on how you've set up your GraphQL schema and root resolver. When using the rootValue approach (as opposed to the more common field resolver approach), you need to be consistent in how you destructure arguments. The library expects resolvers in the same rootValue object to follow the same signature pattern. By making all resolvers use the same pattern, the context is correctly passed as the second parameter.

Key Takeaways

  1. When using graphql-http with rootValue, ensure all resolvers use the same signature pattern
  2. Debug by logging the full context object to see its structure
  3. Remember that GraphQL libraries can have different ways of passing context compared to the standard GraphQL spec
  4. If using TypeScript, properly type your resolver parameters to catch these issues earlier

This pattern issue is easy to miss but can cause frustrating authentication problems in GraphQL applications.

发布评论

评论列表(0)

  1. 暂无评论