RESTful API return 数据是否应该为 UI 重塑
Should a RESTful API return data which is reshaped for the UI
假设一个团队使用 API 到 return 数据到浏览器中的 SPA。
是RESTful到return数据是专门为SPA的UI准备的吗?
相反,客户端可以使用 JS 专门准备数据,这是许多人想要避免的。
重塑是什么意思? =>
public async Task<IEnumerable<SchoolclassCodeDTO>> GetSchoolclassCodesAsync(int schoolyearId)
{
var schoolclassCodes = await schoolclassCodeRepository.GetSchoolclassCodesAsync(schoolyearId);
var allPupils = schoolclassCodes.SelectMany(s => s.Pupils).Distinct<Pupil>(new PupilDistinctComparer());
var allPupilsDTOs = allPupils.Select(p => p.ToPupilDTO());
var schoolclassCodeDTOs = schoolclassCodes.Select(s => s.ToSchoolclassDTO());
// Prepare data specially for UI DataGrid with checkboxes
foreach (var s in schoolclassCodeDTOs)
{
foreach (var p in allPupilsDTOs)
{
var targetPupil = s.Pupils.SingleOrDefault(pupil => pupil.Id == p.Id);
if(targetPupil == null)
{
p.IsSelected = false;
s.Pupils.Add(p);
}
else
{
targetPupil.IsSelected = true;
}
}
}
return schoolclassCodeDTOs;
}
这是个好问题。问题是,很可能只有你自己有答案。
tl;dr 好老"it's application-specific".
您可能需要将其视为一个连续统一体,而不是二元决定。在一个极端,您让服务器生成 HTML 视图,因此要对很多 UI 问题负责,另一方面,您让服务器公开具有非常通用的 CRUD 功能的数据模型,因此不是对任何 UI 问题负责。在中间的某个地方,您还可以找到一种设计,其中服务器接口特定于应用程序但不一定公开 HTML (尽管使用 conn-neg 的魔力一切都到位)可能非常明显的原因(当涉及到所谓的 SPA 时)。
那么,你应该选择什么?
我希望有人建议你尽可能地解耦客户端和服务器,但我个人认为没有这样的终极"good practice"。事实上,这可能为时过早。首先设计您的逻辑组件,然后然后决定它们应该在哪里以及如何运行。
记住:
A good architecture allows major decisions to be deferred and maximizes the number of decisions not made.
(鲍勃叔叔)
为什么?好吧,因为 这些(域逻辑和执行环境)是真正独立的关注点:它们可能会 独立地发展 。例如,如果应用程序是计算密集型的(例如,为了节省电池电量),您可能决定为移动设备创建一个更瘦的客户端,为桌面创建一个更厚的客户端。或者,如果应用程序是网络密集型应用程序,您可能会做完全相反的事情(例如,为了在连接不良时节省往返,也可以考虑 "offline-first")。也许您会提供所有变体并让用户选择,或者可能会根据可用资源自动选择——无论需求如何保证,但它们可能会发生变化。
我认为这些是更合适的问题和做出的体系结构决策(但同样:只有在您已经设计了逻辑组件的边界之后)。这些更明确的要求将帮助您决定您的应用程序的哪些组件应该 运行 放在哪里。他们将驱动您代表您的边界的方式(无论它们是内部的还是远程的APIs,私有的还是public ) 而不是你 塑造 他们的方式(这已经完成了)。您的 RESTful API(如果您决定需要一个并且 REST 风格的架构是合适的)只是任意边界的表示。
这就是您最终在您的场景上下文中回答您自己的问题的方式——希望到那时它应该已经变得非常直观了。
尾注:虽然让域逻辑严格地塑造你的边界是好的和纯粹的,但不可避免地会产生一些与执行环境有关的问题(比如谁控制某些网络主机,数据应该驻留在何处等)回到领域设计。我不认为这是矛盾的;您的应用程序 确实 影响您建模的任何内容 activity,因此它自己的关注点也必须建模。工具也会影响你的思维方式,所以如果 HTTP 是一种工具并且你非常擅长使用它,你可能会开始在任何地方使用它。这不一定是坏事(例如,"micro-services" 尚无定论),但应该意识到了解的工具太少 经常 (并非总是)将开发人员推向尴尬的角落.我怎么能不说完:"use the right tool for th--" 啊,老了是吧;).
假设一个团队使用 API 到 return 数据到浏览器中的 SPA。
是RESTful到return数据是专门为SPA的UI准备的吗?
相反,客户端可以使用 JS 专门准备数据,这是许多人想要避免的。
重塑是什么意思? =>
public async Task<IEnumerable<SchoolclassCodeDTO>> GetSchoolclassCodesAsync(int schoolyearId)
{
var schoolclassCodes = await schoolclassCodeRepository.GetSchoolclassCodesAsync(schoolyearId);
var allPupils = schoolclassCodes.SelectMany(s => s.Pupils).Distinct<Pupil>(new PupilDistinctComparer());
var allPupilsDTOs = allPupils.Select(p => p.ToPupilDTO());
var schoolclassCodeDTOs = schoolclassCodes.Select(s => s.ToSchoolclassDTO());
// Prepare data specially for UI DataGrid with checkboxes
foreach (var s in schoolclassCodeDTOs)
{
foreach (var p in allPupilsDTOs)
{
var targetPupil = s.Pupils.SingleOrDefault(pupil => pupil.Id == p.Id);
if(targetPupil == null)
{
p.IsSelected = false;
s.Pupils.Add(p);
}
else
{
targetPupil.IsSelected = true;
}
}
}
return schoolclassCodeDTOs;
}
这是个好问题。问题是,很可能只有你自己有答案。
tl;dr 好老"it's application-specific".
您可能需要将其视为一个连续统一体,而不是二元决定。在一个极端,您让服务器生成 HTML 视图,因此要对很多 UI 问题负责,另一方面,您让服务器公开具有非常通用的 CRUD 功能的数据模型,因此不是对任何 UI 问题负责。在中间的某个地方,您还可以找到一种设计,其中服务器接口特定于应用程序但不一定公开 HTML (尽管使用 conn-neg 的魔力一切都到位)可能非常明显的原因(当涉及到所谓的 SPA 时)。
那么,你应该选择什么?
我希望有人建议你尽可能地解耦客户端和服务器,但我个人认为没有这样的终极"good practice"。事实上,这可能为时过早。首先设计您的逻辑组件,然后然后决定它们应该在哪里以及如何运行。
记住:
A good architecture allows major decisions to be deferred and maximizes the number of decisions not made.
(鲍勃叔叔)
为什么?好吧,因为 这些(域逻辑和执行环境)是真正独立的关注点:它们可能会 独立地发展 。例如,如果应用程序是计算密集型的(例如,为了节省电池电量),您可能决定为移动设备创建一个更瘦的客户端,为桌面创建一个更厚的客户端。或者,如果应用程序是网络密集型应用程序,您可能会做完全相反的事情(例如,为了在连接不良时节省往返,也可以考虑 "offline-first")。也许您会提供所有变体并让用户选择,或者可能会根据可用资源自动选择——无论需求如何保证,但它们可能会发生变化。
我认为这些是更合适的问题和做出的体系结构决策(但同样:只有在您已经设计了逻辑组件的边界之后)。这些更明确的要求将帮助您决定您的应用程序的哪些组件应该 运行 放在哪里。他们将驱动您代表您的边界的方式(无论它们是内部的还是远程的APIs,私有的还是public ) 而不是你 塑造 他们的方式(这已经完成了)。您的 RESTful API(如果您决定需要一个并且 REST 风格的架构是合适的)只是任意边界的表示。
这就是您最终在您的场景上下文中回答您自己的问题的方式——希望到那时它应该已经变得非常直观了。
尾注:虽然让域逻辑严格地塑造你的边界是好的和纯粹的,但不可避免地会产生一些与执行环境有关的问题(比如谁控制某些网络主机,数据应该驻留在何处等)回到领域设计。我不认为这是矛盾的;您的应用程序 确实 影响您建模的任何内容 activity,因此它自己的关注点也必须建模。工具也会影响你的思维方式,所以如果 HTTP 是一种工具并且你非常擅长使用它,你可能会开始在任何地方使用它。这不一定是坏事(例如,"micro-services" 尚无定论),但应该意识到了解的工具太少 经常 (并非总是)将开发人员推向尴尬的角落.我怎么能不说完:"use the right tool for th--" 啊,老了是吧;).