济南网站优化建设,wordpress做的社交,网站开发图片素材,广西梧州许多人认为GraphQL仅适用于前端和JavaScript#xff0c;它在Java等后端技术中没有定位#xff0c;但事实确实如此。 还经常将GraphQL与REST进行比较#xff0c;但是这种比较是否合理#xff1f; 首先#xff0c;让我开始回答其中最重要的问题。 什么是GraphQL#xff1… 许多人认为GraphQL仅适用于前端和JavaScript它在Java等后端技术中没有定位但事实确实如此。 还经常将GraphQL与REST进行比较但是这种比较是否合理 首先让我开始回答其中最重要的问题。 什么是GraphQL 如果您查看官方网站将会看到类似的内容 “ GraphQL是API的查询语言并且是服务器端运行时用于通过使用为数据定义的类型系统来执行查询。 GraphQL不受任何特定数据库或存储引擎的束缚而是由您现有的代码和数据支持。” 实际上应该说的是 GraphQL是一个规范仅此而已。 要记住这一点很重要因为作为开发人员我们将使用GraphQL的实现。 一些实现已经或多或少地实现了GraphQL规范中的功能。 有许多语言的实现例如JavaScriptJavaPHPGo和其他语言。 每天都有不同语言和现有语言的新实现。 如果您来自Java背景并且有很多REST API那么您首先会感兴趣的是GraphQL与多年来开发的Traditional REST API有何不同。 让我将其放在一个简单的博客的上下文中该博客由博客文章博客文章的作者组成并且可以在博客文章中添加评论。 从数据库的角度来看这意味着我们有三个表 让我们假设前端是只读的并从Traditional REST API获取数据然后将数据呈现给用户。 如果我们要构建这种传统的REST API则可能最终会得到类似以下的代码 RestController public class SimpleRestController { RequestMapping (path /authors ) public List getAllAuthors() { ... } RequestMapping (path /authors/{id} ) public Author getAuthorById( PathVariable String id) { ... } RequestMapping (path /posts ) public List getAllPosts( RequestParam (value author_id , required false ) String authId) { ... } RequestMapping (path /comments ) public List getAllComments( RequestParam (value post_id , required false ) String postId) { ... } } 因此在这种情况下如果我们想显示包含作者信息和评论的帖子我们首先需要致电 /帖子 获取所有帖子然后找到我们想要的帖子查看authorId是什么然后调用 / authours / 帖子中的ID 之后我们需要致电 / commentspost_id 相关帖子的ID 以获取该帖子的所有评论。 显然这不是最佳方法。 当然在这种情况下我们所有人都会做的就是看好我们API的用例并牢记这一点来优化端点和响应。 也许我们会将评论嵌入帖子作者信息或类似内容中。 或者由于某种原因如果我们认为没问题也许我们不会改变任何事情。 无论如何我们将决定用户可以呼叫哪些端点以及他们将获得什么样的响应。 确切地说这是GraphQL的最大区别。 对于GraphQL通常只有一个端点例如 / graphql 该端点将获取对您的API的所有请求并发送回所有响应。 起初听起来有点奇怪。 最简单的方法是拥有完整的示例代码。 我将使用一个这样的示例中的代码片段。 要获取完整的代码只需点击以下URL https://github.com/vladimir-dejanovic/simple-springboot-graphql-mongo-conftalk-demo 要记住的重要一点是在GraphQL中一切都始于架构。 如果我们转到上面的示例博客文章GraphQL模式可能看起来像这样 type Author { id: ID! name: String! posts: [Post] } type Post { id: ID! title: String! body: String createdBy: Author! comments: [Comment] } type Comment { id: ID! createdBy: Author! belongsTo: Post! text: String } schema { query: Query } type Query { allPosts: [Post] allAuthors: [Author] } 我们从定义类型开始对于将为表创建的POJO类型几乎可以是1到1。 首先我们输入一个名称然后输入。 字符 具有特殊含义表示该字段是必填字段。 如果字段具有此字符并且不存在响应则它将是无效响应并且GraphQL将不会将响应发送回去但会发送适当的错误。 关于模式要记住的重要一点是所有请求和响应都将使用模式进行验证。 如果请求未通过架构验证则服务器将不执行任何工作。 另外如果响应未通过架构验证则不会将其发送到客户端。 如果您选中“作者”类型您将看到它具有“帖子数组”类型的字段帖子。 另外Post具有类型为Author和comments的createdBy字段其类型为Comment的Array。 这些字段在POJO的中不存在 Author.java public class Author { private final String id; private final String name; .....get/set } Post.java public class Post { private final String id; private String authorId; private final String title; private final String body; ...get/set } 类似的是注释类型我稍后会再讲。 定义类型之后我们可以进入GraphQL模式的核心 schema { query: Query } 这是我们定义与用户互动的地方。 我们说用户可以使用下面定义的Query类型的查询来读取数据。 type Query { allPosts: [Post] allAuthors: [Author] } Query是一种特殊类型因为我们在DB中没有此数据这实际上是传统思维方式中的端点。 如果您是从GitHub链接下载代码进行编译并启动的则可以转到http// localhost8080 / 。 然后您将看到名为GraphiQL的漂亮用户界面。 您可以使用GraphiQL来玩GraphQL API 为了获得所有带有ID标题和正文的帖子只需将其输入GraphiQL query { allPosts { id title body } } 响应应如下所示 { data : { allPosts : [ { id : 59f4c12e7718af0b1e001072 , title : Who is Ed Wong , body : Edward Wong Hau Pepelu .....” }, . . . . } 例如如果我们对身体不感兴趣我们可以输入这样的内容 query { allPosts { id title } } 那么响应将是这样的 { data : { allPosts : [ { id : 59f4c12e7718af0b1e001072 , title : Who is Ed Wong , }, . . . . } 如您所见当涉及到GraphQL时用户在响应中并不总是获得相同的预定义字段集。 用户可以选择说出哪些字段应该发回哪些不应该。 允许这样做的Java代码不是那么大。 首先我们需要定义扩展SimpleGraphQLServlet的 Servlet。 public class GraphQLEntryPoint extends SimpleGraphQLServlet { public GraphQLEntryPoint(PostRepository postRepository, AuthorRepository authRepository, CommentRepository commentRepository) { super (buildSchema(postRepository, authRepository, commentRepository)); } private static GraphQLSchema buildSchema(PostRepository postRepository, AuthorRepository authRepository, CommentRepository commentRepository) { return SchemaParser .newParser() .file( schema.graphqls ) .resolvers( new Query(postRepository, authRepository), new PostResolver(authRepository, commentRepository), new AuthorResolver(postRepository), new CommentResolver(authRepository, postRepository)) .build() .makeExecutableSchema(); } } 在这里我创建模式解析器该解析器打开我的GraphQL模式文件之后添加解析器然后调用build和makeExecutableSchema方法。 这里的重要部分是解析器。 解析器是GraphQL将用于解决用户请求的类。 首先最重要的是Query类。 它与模式中的Query类型具有相同的名称并非偶然。 这就是java GraphQL实现如何从架构中知道哪个类对应于查询逻辑的。 您可以使用任何喜欢的名称只要该类具有相同的名称即可但是这意味着新人们也需要知道该名称因此请保持标准并且对于只读使用Query。 这是类查询的代码 public class Query implements GraphQLRootResolver { private final PostRepository postRepository; private final AuthorRepository authRepo; public ListPost allPosts() { return postRepository.findAll(); } public ListAuthor allAuthors() { return authRepo.findAll(); } } 它实现了GraphQLRootResolver 并且您可以看到GraphQL模式中的每一行都有一个方法。 有一个叫allPost方法该方法返回后的名单也有方法allAuthors返回作者列表。 为了使我们的API能够正常工作这就是所有这些。 如果您返回到GraphiQL并输入像这样的输入 query { allPosts { id title createdBy { name } } } 响应将是这样的 { data : { allPosts : [ { id : 59f4c12e7718af0b1e001072 , title : Who is Ed Wong , createdBy : { name : Ed Wong” } }, . . . ] } 您会突然得到所有数据而这不是Post pojo的一部分。 正如我们所看到的Query类并没有做任何魔术它只是返回Post类型的普通pojo列表。 那么createdBy字段的作者信息从何而来 为此我们需要查看另一个解析器PostResolver以使其更加精确因此让我们看一下它的代码 public class PostResolver implements GraphQLResolverPost { private final AuthorRepository authRepository; private final CommentRepository commentRepository; public Author createdBy(Post post) { return authRepository.findOne(post.getAuthorId()); } public ListComment comments(Post post) { return commentRepository.findByPostId(post.getId()); } } PostResolver实现了GraphQLResolver 我们不得不说是哪种类型在这种情况下是Post类型 。 如您所见Post中存在模式中的所有字段但Pojo Post中不存在。 有一个createdBy方法该方法采用Post类型的参数并返回Author。 此外还有方法注释 该方法注释也采用Post类型的参数并返回Comment列表。 这就是全部这就是我在代码中使用的GraphQL的java实现如何知道如何解析pojo中不存在的字段的方式。 在pojo的情况下这非常简单如果用户请求该字段则只需调用适当的get方法对于其他字段必须为实现GraphQLResolver的类型提供解析器并且需要一种具有正确签名和返回类型的方法。 如您所见与我们一直以来创建的传统REST API相比使用GraphQL用户可以更好地控制他/她将获取哪些数据以及采用哪种格式。 因此从用户的角度来看这当然具有更好的用户体验因为它具有更大的灵活性。 但是这也意味着后端需要完成许多工作因此系统在高负载下仍能正常运行。 在传统的REST API中作为开发人员我们完全控制用户与端点的交互方式他们将获得什么样的响应以及用户请求将遵循的路径在我们的代码中。 如我们所见使用GraphQL不再是这种情况。 我们知道的是用户将点击解析器而不是如何或通过哪个路径。 因此优化困难得多。 幸运的是并不是所有的东西都丢失了我们仍然可以使用许多旧的技巧来解决这些新的/旧的问题。 例如如果采用传统的REST API解决高性能问题的一种方法是拥有一个带有端点的控制器调用服务然后该服务将承担繁重的工作。 在此设置中我们可以缓存所有对服务的调用并以这种简单的方式获得良好的性能。 我们可以用GraphQL做类似的事情唯一的区别是控制器将调用服务而不是控制器调用服务。 使用GraphQL问题可能会更加棘手但是可以结合使用一些过去的技巧来使用过去的许多技术。 当然每天都会出现许多解决问题的新方法。 我只在这里向您展示了如何读取数据您当然也可以创建/编辑/修改数据并使用GraphQL进行更多操作。 与GraphQL在构建API中提供的功能时我与您分享的内容只是从头开始。 您需要记住的重要一点是尽管GraphQL相对较新但没有它也可以实现它提供的所有功能。 但是在这种情况下您将需要考虑允许用户做什么以及他们如何将请求发送到您的API。 对于GraphQL其他人已经考虑过了而您所要做的就是实现它。 最后GraphQL API是REST API这是高级REST API具有许多功能和特性因此更加精确。 这就是为什么问自己的问题这是一件好事您是否真的需要GraphQL提供的功能并且会为您的API和为此API构建域的域增加更多的问题或解决方案。 也许GraphQL正是您所需要的但也许又是旧的传统REST API所需要的。 资源资源 代码示例https://github.com/vladimir-dejanovic/simple-springboot-graphql-mongo-conftalk-demo GraphQL Java实现https://github.com/graphql-java/graphql-java 弗拉基米尔·德雅诺维奇Vladimir Dejanovic在摩洛哥Devoxx上的Talk GraphQL vs传统REST API https://www.youtube.com/watch?v2FH93GaoIto 翻译自: https://www.javacodegeeks.com/2017/12/gentle-intro-graphql-java-world.html