你不知道的 GraphQL

本文由 kazaff 翻译而成,点击阅读原文可以查看作者的博客,感谢作者的优质输出,让我们的技术世界更加美好✌️

很久之前其实就关注过这个技术,记得当时还是React刚刚崭露头角的时期吧。总之那时候,GraphQL感觉还只是概念完备阶段,除了FB自己内部大量使用外,好像社区并不是很健全,不过大家应该都在疯狂的讨论和跟进吧。过了2年,如今再回过头来看,已经涌现出各种开源或商用服务专注于这个领域,各种语言的框架和工具也都很完备了,感觉是时候重新接触GraphQL了。如果你的项目正处于技术选型,你正在犹豫选择一种接口风格的时刻,不妨了解一下这个神奇而强大的玩意儿~~

本文打算翻译一篇感觉很解惑的文章,主要围绕着GraphQL的server端实现,因为相比client端,server端包含了更多的内容。后面如果有机会,也会尝试提供关于client端相关的内容,不过前端同学可以先看一下这里:howtographql[1],这里有各种最佳实践,应该总会找到和你正在使用相关的前端框架的整合方案,好像有个对应的中文版[2]~

关于GraphQL概念的内容,这篇文章并没有涉及太多,不过假如你用搜索引擎去搜的话,相信有非常多的相关文章供你学习,这里就不再重复了~

原文在这里[3],怀疑我翻译能力的同学可以去看原位哦~

相信读完整个文章,对于GraphQL Server会有一个完整的了解。我们开始吧~

目录

  • 目标

  • 一切从Schema开始

  • 创建一个简单的GraphQL服务端

  • GraphiQL,一个Graphql领域的postman

  • 编写Resolvers

  • 处理数据依赖关系

  • 对接真正的数据库

  • 1+N查询问题

  • 管理自定义Scalar类型

  • 错误处理

  • 日志

  • 认证 & 中间件

  • Resolvers的单元测试

  • 查询引擎的集成化测试

  • Resolvers拆分

  • 组织Schemas

  • 结语

目标

我们的目标是针对一个移动app端界面显示所需要的数据,提供支撑,可以实现单一请求次数下就可以获取足够的数据。我们将会用Nodejs来完成这个任务,因为这个语言我们已经在marmelab用了4年了。但你也可以用任何你想用的语言,例如Ruby,Go,甚至PHP,JAVA或C#。

为了显示这个页面,服务端必须能提供下面的响应数据结构:

{
    "data": {
        "Tweets": [
            {
                "id": 752,
                "body": "consectetur adipisicing elit",
                "date": "2017-07-15T13:17:42.772Z",
                "Author": {
                    "username": "alang",
                    "full_name": "Adrian Lang",
                    "avatar_url": "http://avatar.acme.com/02ac660cdda7a52556faf332e80de6d8"
                }
            },
            {
                "id": 123,
                "body": "Lorem Ipsum dolor sit amet",
                "date": "2017-07-14T12:44:17.449Z",
                "Author": {
                    "username": "creilly17",
                    "full_name": "Carole Reilly",
                    "avatar_url": "http://avatar.acme.com/5be5ce9aba93c62ea7dcdc8abdd0b26b"
                }
            },
            // etc.
        ],
        "User": {
            "full_name": "John Doe"
        },
        "NotificationsMeta": {
            "count": 12
        }
    }
}

我们需要模块化和可维护的代码,需要做单元测试,听起来这很难?你会发现借助于GraphQL工具链,这并不比开发Rest客户端难多少。

一切从Schema开始

当我开发一个GraphQL服务时,我总会从在白板上设计模型开始,而不是上来就写代码。我会和产品和前端开发团队一起来讨论需要提供哪些数据类型,查询或更新操作。如果你了解领域驱动设计方法[4],你会很熟悉这个流程。前端开发团队在拿到服务端返回的数据结构之前是没有办法开始编码的。所以我们需要先对API达成一致。

Tip 命名很重要!不要觉得把时间花在为变量起名字上很浪费。特别是当这些名称会长期使用的时候 - 记住,GraphQL API并没有版本号这回事儿,所以,尽可能让你的Schema具有自解释特性,因为这是其他开发人员了解项目的入口。

下面是我为这个项目提供的GraphQL Schema:

type Tweet {
    id: ID!
    # The tweet text. No more than 140 characters!
    body: String
    # When the tweet was published
    date: Date
    # Who published the tweet
    Author: User
    # Views, retweets, likes, etc
    Stats: Stat
}

type User {
    id: ID!
    username: String
    first_name: String
    last_name: String
    full_name: String
    name: String @deprecated
    avatar_url: Url
}

type Stat {
    views: Int
    likes: Int
    retweets: Int
    responses: Int
}

type Notification {
    id: ID
    date: Date
    type: String
}

type Meta {
    count: Int
}

scalar Url
scalar Date

type Query {
    Tweet(id: ID!): Tweet
    Tweets(limit: Int, sortField: String, sortOrder: String): [Tweet]
    TweetsMeta: Meta
    User: User
    Notifications(limit: Int): [Notification]
    NotificationsMeta: Meta
}

type Mutation {
    createTweet(body: String): Tweet
    deleteTweet(id: ID!): Tweet
    markTweetRead(id: ID!): Boolean
}

我在这个系列的前一篇文章中简短的介绍了Schema的语法。你只需要知道,这里的type类似REST里的resources概念。你可以用它来定义拥有唯一id键的实体(如TweetUser)。你也可以用它来定义值对象,这种类型嵌套在实体内部,因此不需要唯一键(例如Stat)。

Tip 尽可能保证Type足够轻巧,然后利用组合。举个例子,尽管stats数据现在看来和tweet数据关系很近,但是请分开定义它们。因为它们表达的领域不同。这样当有天将stats数据换其它底层架构来维护,你就会庆幸今天做出的这个决定。

QueryMutation关键字有特别的含义,它们用来定义API的入口。所以你不能声明一个自定义类型用这两个关键字 - 它们是GraphQL预留关键字。你可能会对Query下定义的字段有个困扰,它们总是和实体类型名字一样 - 但这只是个习惯约定。我就决定把获取Tweet类型数据的属性名称定义成getTweet - 记住,GraphQL是一种RPC(译者注:有别于RESTful的资源概念)。

官方GraphQL提供的schema文档[5]提供了所有细节,花十分钟来了解一下对你定义自己的schema会很有帮助。

Tip 你可能看过有些GraphQL教程使用代码风格来定义schema,例如GraphQLObjectType。别这么做[6],这种风格显得非常的啰嗦,也不够清晰。

创建一个简单的GraphQL服务端

用Nodejs实现一个HTTP服务端最快的方式是使用express microframework[7]。稍后我们会在http://localhost:4000/graphql[8]下接入一个GraphQL服务。

> npm install express express-graphql graphql-tools graphql --save

express-graphql库会基于我们定义的schemaresolver函数来创建一个graphQL服务。graphql-tools库提供了schema的解析和校验的独立包。这两个库前者是来自于Facebook,后者源于Apollo。

// in src/index.js
const fs = require('fs');
const path = require('path');
const express = require('express');
const graphqlHTTP = require('express-graphql');
const { makeExecutableSchema } = require('graphql-tools');

const schemaFile = path.join(__dirname, 'schema.graphql');
const typeDefs = fs.readFileSync(schemaFile, 'utf8');

const schema = makeExecutableSchema({ typeDefs });
var app = express();
app.use('/graphql', graphqlHTTP({
    schema: schema,
    graphiql: true,
}));
app.listen(4000);
console.log('Running a GraphQL API server at localhost:4000/graphql');

执行下面命令来让我们的服务端跑起来:

> node src/index.js
Running a GraphQL API server at localhost:4000/graphql

我们可以使用curl来简单请求一下我们的graphQL服务:

> curl 'http://localhost:4000/graphql' \
>    -X POST \
>    -H "Content-Type: application/graphql" \
>    -d "{ Tweet(id: 123) { id } }"
{
    "data": {"Tweet":null}
}

正常!

Graphql服务根据我们提供的schema定义,在执行请求携带的查询语句之前进行了必要的校验,如果我们的查询语句中包含了一个没有声明过的字段,我们会得到一个错误提醒:

> curl 'http://localhost:4000/graphql' \
>    -X POST \
>    -H "Content-Type: application/graphql" \
>    -d "{ Tweet(id: 123) { foo } }"
{
    "errors": [
        {
            "message": "Cannot query field \"foo\" on type \"Tweet\".",
            "locations": [{"line":1,"column":26}]
        }
    ]
}

Tipexpress-graphql包生成的GraphQL服务端同时支持GET和POST请求。

Tip 世界上还有一个不错的库可以让我们基于express,koa,HAPI或Restify来建立GraphQL服务:apollo-server[9]。使用的方法和我们用的这个没有太多差异,所以这个教程同样适用。

GraphiQL,一个Graphql领域的postman

curl并不是一个很好用的工具来测试我们的GraphQL服务。我们使用GraphiQL[10]<

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值