yoga710右键无法使用
REST API的设计优雅非常吸引人。 您会得到Google的Adam Bosworth所描述的“简单,轻松,可扩展的扩展”,但并没有获得为获得一致的性能而构建的功能。
现有的REST框架在将您的域模型转换为JSON或XML响应方面做得很好。 但是,它们在每个资源都具有单个文档视图的假设下运行。 每次对资源的请求都将返回整个文档,即使该请求仅需要数据的一部分也是如此。
更重要的是,REST API中的每个GET调用仅返回一种资源类型。 因此,需要聚合来自多种资源类型的数据的请求将需要对每个包含所需结果数据的资源执行至少一个请求。 考虑一下关系数据库世界中的联接查询。 在纯REST模式下,从联接返回的每一行都需要通过网络发出自己的GET请求。 这种闲聊程度很快成为Internet应用程序中的性能瓶颈。
Yoga是一个开源工具包,可与您现有的REST服务器实现集成,并允许您自定义已发布的API。 它为您的GET请求添加了一个选择器 ,该选择器精确指定了您希望从请求中获取的数据,例如关系世界中的列投影子句。 它还具有指定关系表达式的功能,这些关系表达式可以将来自不同相关资源类型的多个文档聚合到单个响应中。
这不是一个新概念。 我们以前在已发布的专有API(例如LinkedIn API的早期版本和Google的GData规范)中已经看到过它。 但是与这些API不同,Yoga允许您将此语法引入自己的Java REST应用程序。
本节的其余部分将演示用例,其中Yoga可以提高应用程序性能,同时保留REST语法的易用性。
这是一个典型的REST请求,用于检索资源实例。 它将返回与User资源类型关联的所有字段:
GET /user/1.json
如果出于安全或性能方面的考虑,您想要生成仅返回给定用户的名称和位置数据的请求,该怎么办? 出于开发目的或发布到受信任的客户端,您可以将选择器附加到请求中:
GET /user/1.json?selector=(id,name,city,state,country)
对于发布公共API,您可能不想为最终用户提供无限的选择器功能。 在这里,您只需将别名发布到定义的选择器:
GET /user/1.json?selector=$locationView
现在,考虑一种情况,您要导航域模型的对象图,并在单个API调用中从多个类返回数据:
上图反映了移动或Javascript客户端使用的数据实体模型,该模型在单个信息屏幕上聚合了许多实体。 客户端发出的一个此类API请求应返回有关用户,他的朋友,他的朋友喜欢的音乐艺术家以及这些艺术家制作的专辑和歌曲的数据(图表中的该路径以栗色突出显示)。
诸如用户,艺术家和歌曲之类的概念是不同的REST资源,因此使用标准REST方法需要进行许多不同的网络调用:
GET /user/1.json (Get user)
GET /user/2.json (Get detailed friend entities)
GET /user/3.json
...
GET /artist/1.json (Get favorite artists)
GET /artist/2.json
...
GET /album/1.json (Get albums for artists)
GET /album/2.json
...
GET /song/1.json (Get songs for albums)
GET /song/2.json
...
显然,这在我们遍历对象图的深度时不会缩放。 网络延迟将很快成为性能瓶颈。
使用选择器,我们可以指定所需的所有数据,并在单个请求中检索它们。 对于开发和受信任的客户,我们可以指定选择器 明确地:
GET /user/1.json?selector=friends(favoriteArtists(albums(songs)))
对于公共API的生产部署,我们可以发布Alias :
GET /user/1.json?selector=$friendsFavoriteMusic
将Yoga添加到您现有的应用程序中只需进行最少的配置更改。 Yoga与Spring MVC REST,Jersey和RESTEasy完美集成。 在下面的示例中,我们将在Spring MVC REST应用程序中实现Yoga。
我们的REST应用程序使用Spring的MappingJacksonJsonView来序列化响应:
<property name= "defaultViews" >
< list >
< bean class= "org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
list >
property >
我们的用户控制器使用可参数化的URI处理对User资源的GET请求,并使用Spring的@ResponseBody批注使用MappingJacksonJsonView呈现输出:
@RequestMapping ( "/user/{id}" )
public @ResponseBody User get( @PathVariable long id )
{
return _userRepository.fetchUser( id );
}
如果需要对呈现用户文档的方式进行更多控制,则可以从REST应用程序迁移到Yoga应用程序。 首先,我们导入我们的Maven依赖项:
<dependency >
< groupId >org.skyscreamer groupId >
< artifactId >yoga-core artifactId >
< version >1.0.0 version >
dependency >
< dependency >
< groupId >org.skyscreamer groupId >
< artifactId >yoga-springmvc artifactId >
< version >1.0.0 version >
dependency >
接下来,我们用YogaSpringView替换Spring的MappingJacksonJsonView,它知道如何解析选择器:
<property name= "defaultViews" >
< list >
< bean class= "org.skyscreamer.yoga.springmvc.view.YogaSpringView" p:yogaView-ref= "jsonView" />
list >
property >
注入的jsonView依赖项告诉SpringMVC Yoga将处理JSON请求并呈现JSON输出。 我们在应用程序上下文中定义jsonView:
<bean name= "jsonView" class= "org.skyscreamer.yoga.view.JsonSelectorView"
p:selectorParser-ref= "selectorParser" />
< bean id= "selectorParser" class= "org.skyscreamer.yoga.selector.parser.GDataSelectorParser" />
在这里,我们还指定GData规范的语法将用于选择器。 Yoga附带了另一个SelectorParser实现,即LinkedInSelectorParser,可供喜欢LinkedIn API选择器格式的开发人员使用。
最后,我们从UserController中删除@ResponseBody批注。 @ResponseBody批注依赖于MappingJacksonJsonView,现在已由YogaSpringView替换。
@RequestMapping ( "/user/{id}" )
public User get( @PathVariable long id )
{
return_userRepository.fetchUser( id );
}
此时,开发人员可以启动Web应用程序,并将适当的选择器附加到资源请求中。
GET /user/1.json?selector=id,name
呈现输出:
{
"name":"Carter Page" ,
"id": 1
}
开发人员可以将favoriteArtists添加到选择器:
GET /user/1.json?selector=id,name,favoriteArtists(id,name)
并向下浏览对象图以查看Artist资源的实例:
{
"id":1 ,
"name": "Carter Page" ,
"favoriteArtists": [
{
"id": 1 ,
"name": "Arcade Fire"
},
{
"id": 3 ,
"name": "Neutral Milk Hotel"
}
]
}
在我们之前的示例中,假设User的id和name字段是必填字段,并且必须为每个User资源请求返回该字段。 这些是便宜的,小的,不可分割的字段,每次创建选择器时都对其进行明确命名可能会变得冗长。
Yoga提供了@Core批注,该批注可应用于您的序列化域模型(或DTO),以标识将始终在Yoga请求中返回的字段。 在这里,我们为User域对象注释getter方法:
@Core
public long getId()
{
return _id;
}
@Core
public String getName()
{
return _name;
}
现在,我们不再需要在选择器中显式请求ID和名称。 以下要求:
GET /user/1.json?selector=favoriteArtists(id,name)
将返回ID,名称以及选择器中指定的其他任何内容:
{
"id": 1 ,
"name": "Carter Page" ,
"favoriteArtists": [
{
"id": 1 ,
"name": "Arcade Fire"
},
{
"id": 3 ,
"name": "Neutral Milk Hotel"
}
]
}
反复优化选择器可加快开发/调试周期。 但是,当您进行API的生产部署时,您可能不希望组成任意选择器的外部用户在您的环境中运行。 对象图的不受限制的导航会Swift导致安全和性能问题。
Yoga允许您为要发布的选择器定义别名,并且仅允许用户调用已定义别名的选择器。 假设我们对以下选择器感到满意,并希望发布它:
?selector=id,name,favoriteArtists(id,name)
首先,在生产配置中,我们将禁用显式选择器的使用,这样该环境中的用户将无法使用GData(或LinkedIn)语法来编写选择器。
<bean id= "selectorParser" class= "org.skyscreamer.yoga.selector.parser.GDataSelectorParser"
p:disableExplicitSelectors= "true" />
接下来,我们定义别名。 瑜伽提供了几种指定别名的机制。 在这种情况下,我们将在属性文件中定义它们。
<bean id= "aliasSelectorResolver" class= "org.skyscreamer.yoga.selector.parser.DynamicPropertyResolver"
p:propertyFile= "classpath:selectorAlias.properties" />
在属性文件中,我们设置别名并命名。 按照惯例,瑜伽别名以$开头:
$userFavoriteArtists=id,name,favoriteArtists(id,name)
现在,在生产环境中,用户可以调用别名,别名的行为在我们的API文档中定义:
GET /user/1.json?selector=$userFavoriteArtists
对于许多开发人员而言,REST模型足以提供对应用程序域的Web API访问。 如果您需要对文档响应的结构进行更细粒度的控制,则Yoga将与您现有的REST应用程序集成,并允许您将选择器添加到Web请求中。
本周,Skyscreamer软件发布了Yoga 1.0版本。 Yoga直接与运行Spring MVC REST,Jersey或RESTEasy实现的Java应用程序集成。 您可以在此链接上找到本文的现场视频演示。
翻译自: https://www.infoq.com/articles/json-yoga/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1
yoga710右键无法使用