一种用于 API 的查询语言。javascript
GraphQL 既是一种用于 API 的查询语言也是一个知足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端可以准确地得到它须要的数据,并且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。html
对比 restful api:java
使用 JavaScript 语言,express node.js 框架开始。node
npm install express express-graphql graphql
建立 server.js 并 使用命令 node server.js
运行 demo。mysql
const express = require('express'); const app = express(); const { graphqlHTTP } = require('express-graphql'); const { buildSchema } = require('graphql'); const schema = buildSchema(` type Query { hello: String } `); const root = { hello: () => 'Hello world!' }; app.use('/graphql', graphqlHTTP({ schema: schema, rootValue: root, graphiql: true, })); app.listen(4000, () => console.log('Now browse to localhost:4000/graphql'));
type Query { rollDice (numDice: Int!, numSide: Int): [Int] }
GraphQL 容许用户自定义参数类型,一般用来描述要获取的资源的属性。sql
type Account { name: String age: Int sex: String department: String salary: (city: String): Int } type Query { account (name: string): Account }
server.js数据库
const schema = buildSchema(` type Account { name: String age: Int sex: String department: String salary(city: String): Int } type Query { hello: String getClassMates(classNo: Int!): [String] account (username: String): Account } `) const root = { hello: () => 'Hello world!', getClassMates: ({ classNo }) => { const obj = { 31: ['张三', '李四', '王五'], 61: ['张大三', '李大四', '王大五'], } return obj[classNo] }, account: ({ username }) => { const name = username const sex = 'nan' const age = 10 const department = '开发部' const salary = ({ city }) => { if (city === '北京' || city === '上海' || city === '深圳' || city === '广州') { return 10000 } return 3000 } return { name, sex, age, department, salary, } }, }
在 server.js 公开文件夹 供用户访问静态资源。express
app.use(express.static('public'))
index.htmlnpm
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <button onclick="getData()">获取数据</button> <script> function getData() { const query = ` query Account ($username: String!) { account(username: $username) { name age sex salary(city: "北京") } }` const variables = { username: '李大四' } fetch('/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ query, variables }) }) .then(res => res.json) .then(json => { console.log(json) }) } </script> </body> </html>
后端的
username
对应variales
的值中的username
, 和query
中的$username
。json
不能单独使用 Mutation
, 需结合 Query
。
const schema = buildSchema(` type Account { name: String age: Int sex: String department: String salary(city: String): Int } input AccountInput { name: String age: Int sex: String department: String salary: Int } type Query { accounts: [Account] } type Mutation { createAccount(input: AccountInput): Account updateAccount(id: ID!, input: AccountInput): Account } `) // 模拟数据库 const fakeDb = {} const root = { createAccount({ input }) { // 模拟数据库保存 fakeDb[input.name] = input // 返回保存结果 return fakeDb[input.name] }, updateAccount({ id, input }) { // 模拟更新数据库 const updatedAccount = Object.assign({}, fakeDb[id], input) fakeDb[id] = updatedAccount return updatedAccount }, accounts() { let arr = [] for (const key in fakeDb) { arr.push(fakeDb[key]) } return arr }, }
试着建立一个 account。
经过 accounts,查询到刚刚建立的 account。
试着修改数据,咱们将 age 18 改成 20,并将该 account 更改后的信息返回。
这里将 name 做为记录的主键了。
上文经过字符串的形式构建 schema
,还能够经过构造函数来构建。
之前:
const schema = buildSchema(` type Account { name: String age: Int sex: String department: String salary(city: String): Int } type Query { account (username: String): Account } `)
如今
const AccountType = new graphql.GraphQLObjectType({ name: 'Account', fields: { name: {type: graphql.GraphQLString}, age: {type: graphiql.GraphQLInt}, sex: {type: raphql.GraphQLString}, department: {type: graphql.GraphQLString}, } }) const queryType = new graphiql.GraphQLObjectType({ name: 'Query', fields: { account: { type: AccountType, args: { username: {type: graphiql.GraphQLString} }, resolve(_, {username}){ const name = username const sex = 'nan' const age = 18 const department = '开发部' return { name, age, sex, department } } } } }) const schema = new graphiql.GraphQLSchema({query: queryType})
代码量提高,编辑器提示,可维护性提高,报错信息更精准。
接下来须要稍做更改,拼接几个 SQL 语句, 操做数据库。
建立数据库 test , 表 account,并添加几个字段以下:
npm i mysql -S
const mysql = require('mysql') const pool = mysql.createPool({ connectionLimit: 10, host: 'localhost', user: 'root', password: '123456', database: 'test', }) const schema = buildSchema(` type Account { name: String age: Int sex: String department: String salary(city: String): Int } input AccountInput { name: String age: Int sex: String department: String salary: Int } type Query { accounts: [Account] } type Mutation { createAccount(input: AccountInput): Account updateAccount(id: ID!, input: AccountInput): Account deleteAccount(id: ID!): Boolean } `) const rootValue = { createAccount({ input }) { const data = { name: input.name, age: input.age, sex: input.sex, department: input.department, } // query 是异步操做, 使用 promise return new Promise((resolve, reject) => { pool.query('insert into account set ?', data, err => { if (err) { console.log('出错了' + err.message) return } resolve(data) }) }) }, deleteAccount({ id }) { return new Promise((resolve, reject) => { pool.query('delete from account where id = ?', id, err => { if (err) { console.log('出错了' + err) reject(false) return } resolve(true) }) }) }, updateAccount({ id, input }) { const data = input return new Promise((resolve, reject) => { pool.query('update account set ? where id = ?', [data, id], err => { if (err) { console.log('出错了' + err.message) return } resolve(data) }) }) }, accounts() { return new Promise((resolve, reject) => { pool.query('select name, age, sex, department from account', (err, res) => { if (err) { console.log('出错了' + err) return } let arr = [] for (let i = 0; i < res.length; i++) { arr.push({ name: res[i].name, sex: res[i].sex, age: res[i].age, department: res[i].department, }) } resolve(arr) }) }) }, }
为方便操做,我将完整代码片断放在最后,供你试一试。
const express = require('express') const app = express() const { graphqlHTTP } = require('express-graphql') const { buildSchema } = require('graphql') const schema = buildSchema(` type Account { name: String age: Int sex: String department: String salary(city: String): Int } input AccountInput { name: String age: Int sex: String department: String salary: Int } type Query { hello: String getClassMates(classNo: Int!): [String] account (username: String): Account accounts: [Account] } type Mutation { createAccount(input: AccountInput): Account updateAccount(id: ID!, input: AccountInput): Account } `) const fakeDb = {} const rootValue = { hello: () => 'Hello world!', getClassMates: ({ classNo }) => { const obj = { 31: ['张三', '李四', '王五'], 61: ['张大三', '李大四', '王大五'], } return obj[classNo] }, account: ({ username }) => { const name = username const sex = 'nan' const age = 10 const department = '开发部' const salary = ({ city }) => { if (city === '北京' || city === '上海' || city === '深圳' || city === '广州') { return 10000 } return 3000 } return { name, sex, age, department, salary, } }, createAccount({ input }) { // 模拟数据库保存 fakeDb[input.name] = input // 返回保存结果 return fakeDb[input.name] }, updateAccount({ id, input }) { // 模拟更新数据库 const updatedAccount = Object.assign({}, fakeDb[id], input) fakeDb[id] = updatedAccount return updatedAccount }, accounts() { let arr = [] for (const key in fakeDb) { arr.push(fakeDb[key]) } return arr }, } // 公开文件夹 供用户访问静态资源 app.use(express.static('public')) // const middleware = (req, res, next) => { // // console.log(req.headers.cookie) // if (req.url.indexOf('/graphql') !== -1) { // res.send( // JSON.stringify({ // error: '您没有权访问这个接口', // }) // ) // return // } // next() // } // app.use(middleware) app.use( '/graphql', graphqlHTTP({ schema, rootValue, graphiql: true, }) ) app.listen(4000, () => console.log('Now browse to localhost:4000/graphql'))
const express = require('express') const app = express() const { graphqlHTTP } = require('express-graphql') const { buildSchema } = require('graphql') const mysql = require('mysql') const { resolve } = require('path') const pool = mysql.createPool({ connectionLimit: 10, host: 'localhost', user: 'root', password: '123456', database: 'test', }) const schema = buildSchema(` type Account { name: String age: Int sex: String department: String salary(city: String): Int } input AccountInput { name: String age: Int sex: String department: String salary: Int } type Query { hello: String getClassMates(classNo: Int!): [String] account (username: String): Account accounts: [Account] } type Mutation { createAccount(input: AccountInput): Account updateAccount(id: ID!, input: AccountInput): Account deleteAccount(id: ID!): Boolean } `) const rootValue = { hello: () => 'Hello world!', getClassMates: ({ classNo }) => { const obj = { 31: ['张三', '李四', '王五'], 61: ['张大三', '李大四', '王大五'], } return obj[classNo] }, account: ({ username }) => { const name = username const sex = 'nan' const age = 10 const department = '开发部' const salary = ({ city }) => { if (city === '北京' || city === '上海' || city === '深圳' || city === '广州') { return 10000 } return 3000 } return { name, sex, age, department, salary, } }, accounts() { return new Promise((resolve, reject) => { pool.query('select name, age, sex, department from account', (err, res) => { if (err) { console.log('出错了' + err) return } let arr = [] for (let i = 0; i < res.length; i++) { arr.push({ name: res[i].name, sex: res[i].sex, age: res[i].age, department: res[i].department, }) } resolve(arr) }) }) }, createAccount({ input }) { const data = { name: input.name, age: input.age, sex: input.sex, department: input.department, } return new Promise((resolve, reject) => { pool.query('insert into account set ?', data, err => { if (err) { console.log('出错了' + err.message) return } resolve(data) }) }) }, updateAccount({ id, input }) { const data = input return new Promise((resolve, reject) => { pool.query('update account set ? where id = ?', [data, id], err => { if (err) { console.log('出错了' + err.message) return } resolve(data) }) }) }, deleteAccount({ id }) { return new Promise((resolve, reject) => { pool.query('delete from account where id = ?', id, err => { if (err) { console.log('出错了' + err) reject(false) return } resolve(true) }) }) }, } // 公开文件夹 供用户访问静态资源 app.use(express.static('public')) app.use( '/graphql', graphqlHTTP({ schema, rootValue, graphiql: true, }) ) app.listen(4000, () => console.log('Now browse to localhost:4000/graphql'))