从零开始尝试在没有数据库的最小配置下运行服务器
GraphQL是一种可以灵活提取数据的API。
大崎在这里。这次我将尽量简单地解释GraphQL并进行试验。如果只是想尝试一下的话,我们还提供了实时演示。
但目前的事实上的API形式是REST。 因此,经常与REST进行比较。
所以,在此先表明結論,這與REST的能力基本相同。
只是,它只稍微有一些針對資料擷取的彈性(能夠撰寫查詢這一個重要特點)。
API这个东西
API的功能不仅仅是获取数据,还可以做以下各种工作,…
-
- トランザクションを無事こなす
非同期処理をスタートする
然而,这次我们将重点放在数据获取上。
(GraphQL也具有数据更新的触发器Mutation,但并不是特别重要,所以将其省略。)
REST的问题:默认情况下缺乏灵活性。
当我们需要某个特定目的的数据时,提供给我们的API所提供的数据可能会有过多或不足。
-
- 目的例
-
- 「近くのレストランの名前を評価順に5個取得する」
-
- 提供されているREST API http:///restaurants/
-
- 市内の全レストランの一覧。
- それぞれに場所と名前とオーナーと電話番号と・・・・・・と従業員を取得する
本来は5つだけ取得するつもりだったが、約1000個ものデータが取得され、不要な値もくっついてくる。
時間もかかる。
必要なデータだけを取り出すことを考えると、以下の例文にあるSQLのようなクエリ言語を思い出すが、残念ながらAPIとして提供されていない。
select restaurant_name from all order by grade limit 5;
有一个名为OData的以SQL over HTTP API形式存在,但有人称其”危险”。或许可以用SOAP来实现,但写XML太麻烦了。
在GraphQL中的灵活性意味着”只需请求所需的数据”。
如果使用GraphQL,它具有灵活性,数据格式与REST相同,使用起来更加方便。
我之前一直以为在REST的POST请求中只能输入查询的方式,然后就发现了GraphQL。
虽然可能不是完美的,因为查询的方式有点不熟悉。
{
restaurants(first: 5, sort: "grade") {
name
}
}
然而,如果您自定义此查询,您可以灵活地更改数据请求,并且可以获得JSON格式的数据。关于灵活性的部分,我们将在试验过程中进行详细说明。
由于返回值是JSON格式,所以您可以充分利用Node等各种强大工具的功能。
您可以像从REST中获取数据一样编写应用程序!
最重要的是先使用GraphQL,甚至可以只用最基本的配置。
GraphQL服务器的最小设置=“仅仅是一个Web服务器(没有数据库)”。
这次基本上是一个原生的GraphQL服务器。
使用的数据是日本城市列表。不过实际上只包含了三鹰市和香取市这两个城市。
只有一个功能,即获取列表。
还不能编写类似的查询。
但先让它运行起来。
服务器的功能有以下三个。
-
- データを保持 (1)
-
- クエリを受け付け (2)
- クエリにあわせたデータを返す (3)
(1) 不需要做任何事情。只要将临时数据放入JSON中即可。
(2) 有幸的是,像apollo-server和graphql-yoga这样的GraphQL服务器会为我们处理所有事务。
(3) 最重要的是,resolver用于编写“对于什么样的查询返回什么样的值”的配置。
准备好了
这次我们将使用Typescript来制作应用程序。
假设环境已经安装了npm和tsc。
我会创建一个文件夹来命名这个GraphQL服务器应用程序。通过npm init来初始化node.js。
graphql-yoga是我们将使用的GraphQL服务器库。
还有一些其他的工具,如apollo-server等,可以使用。
然后,我会安装大约三个启动工具。
$ mkdir sample_app
$ cd sample_app
$ npm init
### 途中のmain指定では index.jsではなくてindex.tsを指定してください。
$ tsc --init
$ npm install graphql-yoga --save
$ npm install nodemon ts-node typescript --save-dev
请在package.json文件中的scripts部分添加一行start命令。希望package.json的内容如下所示。
{
"name": "simple_json_graphql",
"version": "0.0.1",
"description": "Simple GraphQL Server from JSON data",
"main": "index.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon --ext ts,yaml --exec 'ts-node' index.ts"
},
"author": "Hiroyuki OSAKI (https://github.com/onelittlenightmusic)",
"license": "ISC",
"dependencies": {
"graphql-yoga": "^1.16.2"
},
"devDependencies": {
"nodemon": "^1.18.4",
"ts-node": "^7.0.1",
"typescript": "^3.1.1"
}
}
我会创建一个index.ts
我将从刚才解释过的 (1) 开始,逐行写出 (3)。
import { GraphQLServer } from 'graphql-yoga'
// (1)データを保持
const locations = [
{Japanese: "三鷹市",
Prefecture: "Tokyo",
Population: 180797},
{Japanese: '香取市',
Prefecture: 'Chiba',
Population: 85193},
]
// (2)クエリを受け付け
const typeDefs = `
type Location {
Japanese: String
Prefecture: String
Population: Int
}
type Query {
locations: [Location]
}
`;
// (3)クエリにあわせたデータを返す
const resolvers = <any>{
Query: {
locations: () => locations,
},
};
const server = new GraphQLServer({ typeDefs, resolvers })
server.start({port: 4040}, () =>
console.log(`Your GraphQL server is running now ...`),
)
我会逐一解释。
(1) 用汉语自然语言表达如下:
(1) 是将数据以数组的形式直接写入。
所以没有使用数据库。
这些数据是从Wikipedia3上获取的,使用Python进行网页抓取并将其转化为JSON格式。有关Python网页抓取的信息请参考此处。
// (1)データを保持
const locations = [
{Japanese: "三鷹市",
Prefecture: "Tokyo",
Population: 180797},
{Japanese: '香取市',
Prefecture: 'Chiba',
Population: 85193},
]
(2) 创建了数据类型Location和查询locations。这意味着当请求locations查询时,将返回一个数组[Location]。
如果想要了解GraphQL的类型和模式的详细说明,建议查阅官方文档。
// (2)クエリを受け付け
const typeDefs = `
type Location {
Japanese: String
Prefecture: String
Population: Int
}
type Query {
locations: [Location]
}
`;
(3)表明了通过查询返回的值是locations,也就是(1)中的所有值。
这样,GraphQL服务器实现的主要工作是编写处理程序。
// (3)クエリにあわせたデータを返す
const resolvers = {
Query: {
locations: () => locations,
},
};
启动服务器。
$ npm start
我认为GraphQL服务器将在本地主机的4040端口上监听,请通过浏览器进行访问。
GraphQL-Yoga默认集成了一个便捷的查询执行图形用户界面,即GraphQL Playground,并在启动时自动打开。
您应该可以看到该界面。
我尝试执行查询。
GraphQL的查询可以这样编写。
在GraphQL Playground的查询编辑窗格的左侧输入。
{
locations {
Japanese
Prefecture
Population
}
}
你可能已经注意到了,它配备了超强大的补全功能。它可以检查语法错误和类型不匹配。
那么,让我们试着按下中间的按钮。
你有結果了吗?
(1) 刚才输入的数据直接以JSON格式呈现出来了!
确认柔软性(仅需请求所需数据)
我們試著改變一下查詢方式。
假設我們只需要市和縣的名稱,而不需要人口數據。
我将#放在Population之前并注释掉。
{
locations {
Japanese
Prefecture
# Population
}
}
我会试试看。
在前一个查询中,返回了人口数据,但这次没有返回。
换句话说,我认为你会发现只返回了请求的两个字段Japanese(市名)和Prefecture(县名)。
由于它不仅可以作为GUI使用,而且可以直接作为API使用,因此您可以在尝试此GUI的同时实现使用API的应用程序。
顺便提一下,如果将包含所有日本市的Gist数据(自制)进行修改,可以变成类似GitHub仓库的形式。我还添加了部分自制的查询,如果方便的话,请查看一下。
现场演示
我将Heroku上的应用公开,并在graphqlbin上公开了GraphQL Playground。
我将日本的城市列为一张清单,还添加了人口、建立日期等统计数据。
实际上,当在类型上添加注释时,在自动完成和参考右侧的模式窗格时,它会显示类型信息!非常方便。
我计划将市区町村代码随时进行GraphQL化,因为总务省已将其公开。
総務省/全国地方公共団体コード可以用中文翻译成“总务省/全国地方公共团体代码”。
其他的参考资料
Apollo-Server版本最小配置演示
GraphQL 不是 OData
日本城市列表/維基百科