GraphQL 与 DDD 实践

前言

GraphQL 是一种用于 API 的查询语言,它可以让客户端精确地获取需要的数据,避免了传统 RESTful API 中的 over-fetching 和 under-fetching 的问题。而 DDD(领域驱动设计)是一种软件开发方法论,它强调将业务领域的知识和概念直接映射到软件中,从而提高软件的可维护性和可扩展性。本文将介绍如何在前端开发中使用 GraphQL 和 DDD 进行实践。

GraphQL 实践

GraphQL 基础

GraphQL 的核心概念是 schema 和 resolver。Schema 定义了可以查询的字段和类型,Resolver 则定义了如何获取这些字段的值。下面是一个简单的 GraphQL schema:

type Query {
  user(id: ID!): User
}

type User {
  id: ID!
  name: String!
  email: String!
}

这个 schema 定义了一个 user 查询,它接受一个 id 参数,并返回一个 User 类型的对象。User 对象包含了 idnameemail 三个字段。

Resolver 则定义了如何获取这些字段的值。下面是一个简单的 Resolver:

const resolvers = {
  Query: {
    user: (_, { id }) => {
      return getUserById(id);
    },
  },
};

这个 Resolver 定义了一个 user 方法,它接受一个 _ 参数和一个 { id } 参数。_ 参数表示父级对象,这里不需要使用,{ id } 参数则是前端传入的参数。getUserById(id) 则是一个异步方法,用来获取指定 id 的用户信息。

GraphQL 和 React

在 React 中使用 GraphQL 可以使用 react-apollo 这个库。下面是一个简单的例子:

import React from 'react';
import { Query } from 'react-apollo';
import gql from 'graphql-tag';

const GET_USER = gql`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
`;

const User = ({ id }) => (
  <Query query={GET_USER} variables={{ id }}>
    {({ loading, error, data }) => {
      if (loading) return <p>Loading...</p>;
      if (error) return <p>Error :(</p>;

      const { user } = data;
      return (
        <div>
          <p>{user.name}</p>
          <p>{user.email}</p>
        </div>
      );
    }}
  </Query>
);

export default User;

这个例子定义了一个 User 组件,它接受一个 id 参数。在组件内部使用 Query 组件来查询用户信息。query 属性定义了查询语句,variables 属性定义了查询参数。loadingerrordata 则是 Query 组件返回的结果,根据它们的值来渲染组件。

GraphQL 和 TypeScript

在 TypeScript 中使用 GraphQL 可以使用 graphql-codegen 这个库。它可以根据 GraphQL schema 自动生成 TypeScript 类型和 Resolver 代码。下面是一个简单的例子:

type Query {
  user(id: ID!): User
}

type User {
  id: ID!
  name: String!
  email: String!
}
import { IResolvers } from 'graphql-tools';
import { User } from './generated/graphql';

const resolvers: IResolvers = {
  Query: {
    user: (_, { id }): User => {
      return getUserById(id);
    },
  },
};
import { DocumentNode } from 'graphql';
import gql from 'graphql-tag';
import { User } from './generated/graphql';

export interface GetUserQueryVariables {
  id: string;
}

export interface GetUserQueryData {
  user: User;
}

export const GET_USER_QUERY: DocumentNode = gql`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
`;

这个例子定义了一个 GraphQL schema、一个 Resolver 和一个查询语句。然后使用 graphql-codegen 自动生成了 TypeScript 类型和 Resolver 代码。在前端代码中使用这些类型和查询语句,可以大大提高代码的可读性和可维护性。

DDD 实践

DDD 基础

DDD 的核心概念是领域模型、领域服务和领域事件。领域模型是业务领域的核心概念和知识,它应该直接映射到软件中。领域服务是一组操作,它们可以操作领域模型并实现业务逻辑。领域事件是领域模型中发生的事件,它们可以被其他领域模型或业务逻辑捕获并做出相应的响应。

下面是一个简单的领域模型:

class User {
  id: string;
  name: string;
  email: string;

  constructor(id: string, name: string, email: string) {
    this.id = id;
    this.name = name;
    this.email = email;
  }
}

这个领域模型定义了一个用户,它包含了 idnameemail 三个属性。它的构造函数接受这三个属性作为参数,并将它们保存在对象中。

下面是一个简单的领域服务:

class UserService {
  async getUserById(id: string): Promise<User> {
    // ...
  }

  async createUser(name: string, email: string): Promise<User> {
    // ...
  }

  async updateUser(id: string, name?: string, email?: string): Promise<User> {
    // ...
  }

  async deleteUser(id: string): Promise<void> {
    // ...
  }
}

这个领域服务定义了一组操作,它们可以操作用户对象并实现业务逻辑。比如,getUserById 方法可以根据用户 ID 获取用户对象;createUser 方法可以创建一个新的用户对象,并将它保存到数据库中;updateUser 方法可以更新一个已有的用户对象;deleteUser 方法可以删除一个已有的用户对象。

DDD 和 GraphQL

GraphQL 和 DDD 都是基于领域模型的,它们可以很好地结合起来。下面是一个简单的例子:

type Query {
  user(id: ID!): User
}

type Mutation {
  createUser(name: String!, email: String!): User
  updateUser(id: ID!, name: String, email: String): User
  deleteUser(id: ID!): Boolean
}

type User {
  id: ID!
  name: String!
  email: String!
}

这个 GraphQL schema 定义了一个 user 查询和三个变更操作。user 查询接受一个 id 参数,并返回一个 User 类型的对象。三个变更操作分别是 createUserupdateUserdeleteUser,它们分别接受不同的参数,并返回一个 User 类型的对象或一个布尔值。

下面是一个简单的 Resolver:

const resolvers = {
  Query: {
    user: (_, { id }) => {
      return userService.getUserById(id);
    },
  },
  Mutation: {
    createUser: (_, { name, email }) => {
      return userService.createUser(name, email);
    },
    updateUser: (_, { id, name, email }) => {
      return userService.updateUser(id, name, email);
    },
    deleteUser: (_, { id }) => {
      return userService.deleteUser(id);
    },
  },
};

这个 Resolver 定义了一个 user 查询和三个变更操作的实现。它们都使用了之前定义的领域服务。

总结

本文介绍了如何在前端开发中使用 GraphQL 和 DDD 进行实践。GraphQL 可以让客户端精确地获取需要的数据,避免了传统 RESTful API 中的 over-fetching 和 under-fetching 的问题。DDD 则强调将业务领域的知识和概念直接映射到软件中,从而提高软件的可维护性和可扩展性。两者结合起来,可以让前端开发更加高效和优雅。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/658ab052eb4cecbf2dff0ee5


纠错
反馈