做Apollo服务器端逻辑的设计模式是什么

What is the design pattern for doing Apollo serverside logic

提问人:aProfessionalHelpNeeder 提问时间:8/31/2023 更新时间:9/9/2023 访问量:26

问:

为了学习 GraphQL 和 Apollo,我正在开发一个井字游戏。目前它的工作方式是服务器存储所有游戏信息,因此当客户端单击一个方块时,它会向服务器发送一个突变,该服务器更新游戏状态类型并返回新状态。我想要的是让服务器处理所有游戏逻辑,例如检查移动是否合法、玩计算机移动、检查获胜者,然后返回新的 GameState。

我最初的想法是将所有这些逻辑都放在突变解析器中,但在我遵循的教程中,强烈建议将解析器保持尽可能小,这样看起来不是最好的设计。我想不出其他方法可以做到这一点,Apollo服务器通常不以这种方式使用吗?

可能相关的代码:

图式:

const typeDefs = gql`
    type GameState {
        board: [[String!]!]!
        status: String!
        winner: String
    }
    type Mutation {
        placeO(x: Int!, y: Int!): GameState
    }
    type Query {
        "Query to get tracks array for the homepage grid"
        getGameState: GameState
    }
`;

突变解析器:

  Mutation: {
    placeO: (_, { x, y }, { dataSources }) => {
      // check_legal_move(x, y, dataSources.state.board); ??
      dataSources.state.board[x][y] = 'O';
      // computer_move(dataSources.state.board); ??
      return dataSources.state;
    }
  },

客户端变更请求:

const PLACE_O = gql`
    mutation placeO($x: Int!, $y: Int!) {
        placeO(x: $x, y: $y) {
            board,
            status,
            winner,
        }
    }
`;
graphql logic 服务器端 apollo-server

评论


答:

1赞 Dan Crews 9/9/2023 #1

强烈建议将解析器保持在尽可能小的范围内

它的意思是:作为一般规则,GraphQL 层(与任何 API 实现层一样)应被视为“转换器”。它应该:

  1. 接受传入的 GraphQL 输入
  2. 将其转换为函数调用
  3. 调用函数
  4. 接受函数输出
  5. 将其转换为 GraphQL 输出
  6. 返回 GraphQL 输出

在您的示例中,它可能如下所示:

const resolvers = {
  Mutation: {
    placeO: (_, { x, y }, { dataSources }) => {
      return dataSources.game.placeMark({ x, y, value: 'O' });
    }
  },
}

与其说你的 dataSource 是状态,不如说它应该你做业务逻辑的地方,它将控制从那里发生的事情。dataSource 将包含类似于解析器中的内容

{
  placeMark({ x, y, value }) {
    const state = this.getState();
    // check_legal_move(x, y, state.board); ??
    state.board[x][y] = 'O';
    // computer_move(state.board); ??
    return state;
  }
}

但是Daaan,为什么我不应该在解析器中这样做呢?

问得好。这个问题的一个答案是单一责任原则,它不会让你在同一个地方做路由、业务逻辑和状态管理。虽然遵循这个原则并不总是“最有效的”、“最好的答案”,甚至在极少数情况下是“正确的答案”,但知道何时在应用程序设计中使用这种模式将在整个职业生涯中对你有好处。

我在 GraphQL 上看到的最大价值在于,它有助于 GraphQL 是“一个图”。你所做的事情,你所代表的数据都只是连接海洋中的节点,你将添加新连接,删除旧连接,弃用东西,将一行从节点 A 重新指向节点 B,以便现在它转到节点 C,你不想担心 a) 破坏你现有的 API 或 b) 复制/粘贴你所有的业务逻辑。

假设您想进行通用突变,这样您就不必分别执行 Xs 和 O。在不破坏任何内容的情况下,您可以添加:

const resolvers = {
  Mutation: {
    placeO: (_, { x, y }, { dataSources }) => {
      return dataSources.game.placeMark({ x, y, value: 'O' });
    }
    placeMark: (_, { x, y, value }, { dataSources }) => {
      return dataSources.game.placeMark({ x, y, value });
    }
  },
}