使用 GraphQL API 的清洁架构 CQRS
Posted
技术标签:
【中文标题】使用 GraphQL API 的清洁架构 CQRS【英文标题】:Clean Architecture CQRS with GraphQL API 【发布时间】:2020-11-20 13:43:06 【问题描述】:我正在使用 API 服务器 (ASP.NET Core)。 为了防止将来出现意大利面条式代码和其他令人讨厌的事情,我按照 Clean Architecture/CQRS(使用 MediatR)设计了系统。
我正在考虑将 GraphQL 用于 API,而不是 REST(热巧克力 GraphQL)。 在 HotChocolate GraphQL 的几个示例中,使用 GraphQL-EF 机制直接查询数据库。虽然这看起来很有好处,但我担心从长远来看这可能会使代码复杂化。数据库结构可能会发生变化,等等。在我看来,API 应该与存储库层保持分离。 即使做更多工作,我相信 GraphQL 应该改为与 CQRS 通信。
你的想法,请!
【问题讨论】:
【参考方案1】:您是否考虑过将 GraphQL 用于 CQRS 中的 Q 以及其他一些 RPC 机制用于 CQRS 的命令端?
Mark Grenfell 在其关于 gRPC 的伦敦 2020 NDC 演讲中强调了在没有 api 版本控制的情况下支持可演化灵活性的重要性,这一点似乎证实了您对数据库架构和 GraphQL 之间紧密耦合的担忧。
国家数据中心谈话:From WCF to gRPC - Mark Rendle | NDC Conferences
以下博客文章演示了如何使用动态类型创建成形实体框架查询。我还没有探索如何将这种技术与 GraphQL 挂钩,但这可能会提供足够的模式抽象。
CQRS with Entity Framework Core
【讨论】:
【参考方案2】:这只是 GraphQL 的冰山一角,使用它还有更多我将要向您展示的内容。只是想把它作为免责声明。
使用 GraphQL 时,您有一个继承自 ObjectGraphType 的 Query 对象和一个继承自的 Schema 对象,以实现您的自定义查询、订阅和突变。
这些示例用于处理管理员问题的服务,这就是为什么您会经常看到“管理员”一词。
这个实现的核心是一个继承自 ObjectGraphType 的对象:
public class AdminQuery : ObjectGraphType
public AdminQuery(IServiceProvider sp)
///Used to retrieve a list of users
Field<ListGraphType<UserType>>()
.Name("users")
.Description(nameof(User))
.ResolveAsync(
async context
=> await sp.GetAsync<User>()); ////This is the extension method defined below
///GraphQL object that represents the User object
///Since there were numerous data models I created an abstract class
///to offload some of the boiler plate code
public class UserType : IdentityDataTypeBase<User>
public UserType(IServiceProvider sp) : base()
///This allows access to the properties of the User class
///The second parameter determines whether to allow null
Field(c => c.Name, true);
Field(c => c.Email, true);
Field(c => c.FirstName, true);
Field(c => c.LastName, true);
Field(c => c.UserName, true);
///Abstract class that handles Identity Models being queried
public abstract class IdentityDataTypeBase<T> : ObjectGraphType<T> where T : IdentityBase
public IdentityDataTypeBase()
Field(c => c.Id, false)
.Name(///Name of your property)
.Description(///Description of the property);
///Extension method defined to simplify data access
public static Task<IEnumerable<T>> GetAsync<T>(this IServiceProvider sp)
///if you use IRepository<T>
var repo = sp.GetRequiredService<IRepository<T>>();
///if you want to directly us the DbContext
var repo = sp.GetRequiredService<DbContext>();
///Use the instance of whichever to retrive the object from the database
此示例希望表明您只需要访问您正在查询的数据模型以及您将用于访问该数据的数据存储。
【讨论】:
您不应该使用存储库模式 - DbContext 已经是 UoW。【参考方案3】:当您考虑 GraphQL 时,请查看 GraphQL 需要访问的不同内容。我需要访问表示数据的模型,并且它需要访问数据源,无论是 DbContext 类还是 IRepository。您从实际实现中抽象得越多,您就越能将自己与重大更改隔离开来。我在上一个项目中实现了 GraphQL,并为所有与 GraphQL 相关的类创建了一个单独的库。 GraphQL 库只需要访问带有数据模型的库,它也有接口。然后应用层只需引用 GraphQL 库,就可以调用将其插入 DI 管道的扩展方法。
【讨论】:
你有样品给我吗? @韦恩戴维斯【参考方案4】:尽管不是封闭式回答“是或否”的问题,但我同意你的看法。我怀疑这些例子中的大多数可能只是为了演示。如果不分离合约、业务逻辑和数据层,似乎很难确保 SOLID 原则。
像您一样使用 CQRS 和 MediatR,您可以更轻松地执行 DDD。因此,命令/查询位于 Application 层似乎很自然,而存储库的实现可以转到 Infrastructure。另一方面,API 合约将进入 Presentation 层。
事实上,我们可以在Application 层中自始至终开发多个功能,具体取决于我们的业务需求。这些功能可以提供各种 Presentation 模块,以不同方式公开的 API、UI 应用等。另一方面,这些功能可以依赖于各种 Infrastructure 数据存储库或外部例如来源。
Microsoft 对常见的 Web 架构 here 进行了很好的分析,重点关注 Clean Architecture here。
最后,在我看来,是的,您可以在 Presentation 中设置 GraphQL API,您的业务逻辑在 Application 层中使用 CQRS 设计并使用 MediatR 进行编排,以及在基础设施中实现的数据存储库(尊重应用程序中定义的合同/接口)。
【讨论】:
以上是关于使用 GraphQL API 的清洁架构 CQRS的主要内容,如果未能解决你的问题,请参考以下文章