You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js代码迁移至Apollo Server:业务逻辑适配Resolver咨询

Migrating Express Route Logic to Apollo Server Resolvers

Hey there! I’ve been in your exact situation when moving from Express routes to Apollo Server, so let’s walk through the most straightforward ways to reuse your existing user-handling and business logic in resolvers.

The Core Idea: Use Apollo’s context as Your "Req Object"

In Express, you pass data between middleware via req; in Apollo, the equivalent is the context object—it’s available to every resolver, making it perfect for sharing the user object across your GraphQL operations.

Step 1: Inject the User into Apollo Context

First, you’ll want to move your existing user-fetching logic into Apollo’s context setup. You can choose either of these options based on your existing code structure:

Option A: Reuse Your Existing Express Middleware

If you still want to leverage your original Express middleware to populate req.user, just mount Apollo after that middleware runs:

// Your existing Express middleware that sets req.user
app.use(async (req, res, next) => {
  req.user = await fetchUserFromDatabaseOrToken(req); // Your existing logic
  next();
});

// Mount Apollo Server on the /graphql route
app.use('/graphql', expressMiddleware(server));

Then, pass the pre-populated req.user into Apollo’s context:

const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: ({ req }) => {
    // Now every resolver can access context.user
    return { user: req.user };
  },
});
Option B: Move User Logic Directly into Context

If you want to cut out the Express middleware middleman, handle user fetching directly in the context function:

const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: async ({ req }) => {
    // Run your existing user-fetching logic here
    const user = await fetchUserFromDatabaseOrToken(req);
    return { user };
  },
});

Step 2: Adjust Your Business Logic to Be Reusable

Your original createToken function probably depends on req.user. Let’s refactor it to accept a user parameter directly—this makes it usable in both Express and Apollo resolvers:

Before (Express-specific):

function createToken(req, res, next) {
  const token = generateAuthToken(req.user);
  res.send({ token });
  next();
}

After (Reusable):

export function createToken(user) {
  return generateAuthToken(user); // Pure function, no dependency on req/res
}

Step 3: Use the User in Resolvers

Now you can easily access context.user in any resolver and call your refactored business logic:

const resolvers = {
  Query: {
    currentUser: (_, __, context) => {
      // Return the user from context, just like you would from req.user
      return context.user;
    },
  },
  Mutation: {
    generateUserToken: (_, __, context) => {
      if (!context.user) {
        throw new Error("You need to be logged in to create a token");
      }
      // Call your reusable createToken function
      const token = createToken(context.user);
      return { token, user: context.user };
    },
  },
};

Bonus: Handle Auth Checks with Custom Directives

If you have multiple resolvers that require a logged-in user (like your old Express auth middleware), you can create a custom GraphQL directive to avoid repeating code:

  1. Define the directive in your schema:
directive @requireAuth on FIELD_DEFINITION

type Query {
  currentUser: User @requireAuth
}

type Mutation {
  generateUserToken: TokenPayload @requireAuth
}
  1. Implement the directive logic:
const { SchemaDirectiveVisitor } = require('apollo-server-express');
const { defaultFieldResolver } = require('graphql');

class RequireAuthDirective extends SchemaDirectiveVisitor {
  visitFieldDefinition(field) {
    const originalResolver = field.resolve || defaultFieldResolver;

    field.resolve = async (...args) => {
      const context = args[2];
      if (!context.user) {
        throw new Error("Authentication required for this operation");
      }
      // Call the original resolver if the user is authenticated
      return originalResolver.apply(this, args);
    };
  }
}
  1. Add it to your Apollo Server config:
const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: ({ req }) => ({ user: req.user }),
  schemaDirectives: {
    requireAuth: RequireAuthDirective,
  },
});

Now any field marked with @requireAuth will automatically check for a valid user in the context—no need to add the check to every resolver!

Key Takeaways

  • Treat Apollo’s context like your Express req object for sharing data across resolvers
  • Refactor business logic to be pure functions (no req/res dependencies) for maximum reusability
  • Use custom directives to replicate middleware-like behavior (auth checks, etc.) in GraphQL

内容的提问来源于stack exchange,提问作者JamesG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:20:22