该文章由Panayiotis«pvgr»Velisarakos进行了同行评审。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态!
假设您想按照食谱烤蛋糕。 您将需要一些成分,并且每种成分都需要适当的数量。 如果您可以得到一个装有您配方所需所有成分的盒子,已经过测量和称重以匹配您的配方,该怎么办? 它肯定会使烘焙容易得多。 如果您将前端UI视为蛋糕,这就是GraphQL的目的。
在本教程中,我们将编写一个小型GraphQL服务器来响应来自Todo List应用程序的请求。 您可以在那边的许多应用程序中进行选择,但是由于这些天我正在从事React项目,因此我将选择React作为前端框架。 但是,请随时选择您喜欢的任何其他JavaScript框架。
GraphQL
GraphQL允许我们定义一个查询,该查询提供了客户端和服务器之间的公共接口,用于数据获取和操作。 它处理一种查询语言,该语言允许客户端描述其所需的数据及其形状,该语言旨在通过提供直观而灵活的语法来构建客户端应用程序。
这使得从服务器检索数据对于客户端而言更加有效。 例如,假设客户端仅需要GraphQL的实现中的title
和id
,那么它应该执行以下操作:
query Query {
todos {
id,
title
}
}
产生结果数据(JSON):
{
"data": {
"todos": [
{
"id": 1446412739542,
"title": "Read emails"
},
{
"id": 1446412740883,
"title": "Buy orange"
},
{
"id": 1446412741215,
"title": "Fix garbage"
}
]
}
}
也许在我们的现场演示中尚未保存任何数据。 其背后的原因是,每当我们运行服务器时,存储Todo的内存中的阵列就会变空。 在以下各节中,我们将看到如何在该数组中添加数据。
可以看到,响应格式在查询中描述,由客户端而不是服务器定义。 如标题为“ GraphQL概述– GraphQL和Node.js入门”的文章所述,
GraphQL查询就像没有属性的JSON对象。 重要的是要提一下GraphQL不是特定于语言的 ,它只是客户端和服务器之间的规范。 如果客户端说通用语言,则任何客户端都应该能够与任何服务器进行通信。
GraphQL.js简介
GraphQL.js是GraphQL for JavaScript的参考实现,它提供两个重要功能:
- 建立类型架构。
- 针对该类型架构的查询。
需要构建一个映射到代码库的GraphQL类型架构。 在下面的代码中,我们定义了一个简单的架构。 它具有一种类型和一个解析为固定值的Todo(s)
列表(每个元素具有三个字段)。 另外,还需要针对该类型架构提供查询结果。
var graphql = require ('graphql');
// Here is some dummy data to make this piece of code simpler.
// It will be changeable after introducing mutation.
var TODOs = [
{
"id": 1446412739542,
"title": "Read emails",
"completed": false
},
{
"id": 1446412740883,
"title": "Buy orange",
"completed": true
}
];
var TodoType = new graphql.GraphQLObjectType({
name: 'todo',
fields: function () {
return {
id: {
type: graphql.GraphQLInt
},
title: {
type: graphql.GraphQLString
},
completed: {
type: graphql.GraphQLBoolean
}
}
}
});
var queryType = new graphql.GraphQLObjectType({
name: 'Query',
fields: function () {
return {
todos: {
type: new graphql.GraphQLList(TodoType),
resolve: function () {
return TODOs;
}
}
}
}
});
module.exports = new graphql.GraphQLSchema({
query: queryType
});
现在,让我们看一下JavaScript文件的代码,该代码为我们提供JSON中的结果数据:
var graphql = require ('graphql').graphql
var express = require('express')
var graphQLHTTP = require('express-graphql')
var Schema = require('./schema')
var query = 'query { todos { id, title, completed } }'
graphql(Schema, query).then( function(result) {
console.log(JSON.stringify(result));
// Prints
// {
// "data":{
// "todos":[
// {
// "id":1446412739542,
// "title":"Read emails",
// "completed":false
// },
// {
// "id":1446412740883,
// "title":"Buy orange",
// "completed":true
// }
// ]
// }
// }
});
var app = express()
.use('/', graphQLHTTP({ schema: Schema, pretty: true }))
.listen(8080, function (err) {
console.log('GraphQL Server is now running on localhost:8080');
});
通过运行下面的代码,可以获得上面的代码给出的相同结果。 为了在此示例上获得更多优势, cURL
不是必需的。 这是在不点击浏览器示例的情况下检索数据的更简单方法。 请注意,如果您是Window用户,则可以使用Windows命令提示符运行cURL
示例 。 此外, 在这里您可以找到一个很好的资源来学习如何在系统上安装cURL
。
$ curl -XPOST -H "Content-Type:application/graphql" -d 'query { todos { title } }' http://localhost:8080
{
"data": {
"todos": [
{
"title": "Read emails"
},
{
"title": "Buy orange"
}
]
}
}
该模式的重要之处在于,它不假设数据的存储方式,因为它仅描述了API使用者可以使用的内容。 数据的存储和表示方式是实现细节。
反应
React是一个JavaScript库,用于创建由Facebook和Instagram开发的用户界面。 许多人选择将React视为MVC模式中的V。 如官方网站所述 ,
我们构建React来解决一个问题:使用随时间变化的数据构建大型应用程序。 这都是关于构建可重用组件的。 实际上,唯一的事情就是构建组件。
如果需要React指南,可以阅读和观看以下资源:
一个简单的React组件
React组件实现了render()
方法,该方法获取输入数据并返回要显示的内容。 本示例使用了一种称为JSX的类似XML的语法 。 JSX是可选的,不需要使用React。 JSX是一个JavaScript语法扩展,看起来类似于XML。 您可以在React中使用简单的JSX语法转换。
可以通过render()
。 render()
通过this.props
访问传递到组件的输入数据。 下面报告了一个如何创建React组件的简单示例,它也可以作为CodePen获得 。
var Application = React.createClass({ render: function() { return
{ this.props.text } { this.props.id }; } });
有了前面的代码,这就是JSX编译器生成的原始JavaScript代码。
"use strict";
var Application = React.createClass({
displayName: "Application",
render: function render() {
return React.createElement(
"div",
null,
this.props.text,
this.props.id
);
}
});
如果您想进一步研究React组件,请花一点时间看一下视频Component State Introduction 。
示例中的演练
首先,我们需要一台服务器(已启动并正在运行),以从Todo List应用程序接收GraphQL查询。 该服务器已在上面编写。
要运行我们的服务器,请在CLI上执行:
$ git clone https://github.com/sitepoint-editors/todo-graphql-server.git
$ cd todo-graphql-server
$ npm install
$ npm start
您必须具有Node v4.0.0或更高版本,因为服务器代码使用的是旧版本不支持的ES2015功能 。
现在,将针对我们的GraphQL模式执行对端点/graphql
所有POST请求。 要测试一切正常,请键入以下代码:
$ curl -XPOST -H "Content-Type:application/graphql" -d 'query { todos { title } }' http://localhost:8080
{
"data": {
"todos": []
}
}
尚未保存任何数据。 因此,每次我们运行服务器时,存储todo(s)
内存中的阵列都会为空。 当然,我们不希望对空数组进行只读访问。 我们必须添加和更改数据。 这种有副作用的操作在GraphQL中称为突变 。 定义突变与定义查询相同,并且还会返回类型化的值。 这个想法是,如果某些东西发生了突变,那么它将返回任何被突变的东西。
var MutationAdd = {
type: new GraphQLList(TodoType),
description: 'Add a Todo',
args: {
title: {
name: 'Todo title',
type: new GraphQLNonNull(GraphQLString)
}
},
resolve: (root, {title}) => {
TODOs.push({
id: (new Date()).getTime(),
title: title,
completed: false
});
return TODOs;
}
};
var MutationType = new GraphQLObjectType({
name: 'Mutation',
fields: {
add: MutationAdd
}
});
export var Schema = new GraphQLSchema({
query: QueryType,
mutation: MutationType
});
上方的箭头( =>
)是定义函数的新语法 。 ES2015最有趣的新部分之一。
正如Clay Allsopp撰写的标题为“您的第一台GraphQL服务器”的文章中所述,
突变和查询之间的有意义的区别是,突变是按顺序处理的,但是查询没有这样的保证(实际上,GraphQL鼓励服务器利用独立查询的固有并行性)。 GraphQL规范给出了一组突变查询的示例,这些突变查询必须由服务器按顺序处理:
{
first: changeTheNumber(newNumber: 1) {
theNumber
},
second: changeTheNumber(newNumber: 3) {
theNumber
},
third: changeTheNumber(newNumber: 2) {
theNumber
}
}
因此,在请求结束时, theNumber
字段的值应为2
。 在快速介绍了变异之后,我们终于可以在服务器中添加一个todo
。
$ curl -XPOST -H "Content-Type:application/graphql" -d 'mutation { add (title: "Clean garage") { id, title } }' http://localhost:8080
{
"data": {
"add": [
{
"id": 1446443172937,
"title": "Clean garage"
}
]
}
}
很酷,不是吗? 除了这个add突变,我们还有更多的东西: toggle
, toggleAll
, destroy
, clearCompleted
。 并save
。 要注意的一件事是,我们在所有突变中都传递了参数。 所有字段都可以接受参数。 创建参数非常简单,可以将它们加入函数 resolve
。
归根结底,我们有两种查询类型:
- 一种用于从服务器获取( 获取 )数据的程序;
- 一种用于处理( 创建 , 更新 , 删除 )数据的工具。
在运行服务器的情况下,我们准备使用在React中创建的Todo列表: React TodoMVC Example的一个分支 ,如开始所述。 要下载它,执行:
$ git clone -b react-graphql https://github.com/sitepoint-editors/todomvc.git
$ cd todomvc
$ npm install
$ node server.js
转到http://localhost:3000
查看正在运行的应用程序。 与原始代码相比,此代码有两个主要更改。 首先, TodoModel
已更改为到达GraphQL服务器。
其次,服务器中的代理将GraphQL请求重定向到我们创建的服务器。 有关更多详细信息,请参见下面的图像。
结论
正如您在本教程中所看到的那样,GraphQL和GraphQL.js是Facebook在2015年作为一组开源项目发布的相当新的技术。核心思想是UI最清楚呈现一组特定组件所需的数据。 。 如果您尝试从MVC Todo List中选择另一个JS框架并且遇到任何问题,请放下一行。 谢谢阅读。